Build an Anjuna Confidential Pod image
If you have not already done so, follow the guide Example 1 - Deploy Nginx as an Anjuna Confidential Pod. It goes into more detail on the process of building Anjuna Confidential Pod (Confidential Pod) images.
In this example, you will build a custom application from scratch that uses some of the features of the Anjuna Confidential Pod Configuration File.
Build a container
Start by building a simple Docker container.
First, cd into a new temporary directory.
$ cd $(mktemp -d)
Then, run the following command to create the Dockerfile,
which defines an image that writes its logs to a file in a shared directory,
not to standard output.
The application first records its environment using the env command,
then appends a log line every second:
$ cat <<EOF > Dockerfile
FROM alpine:latest
CMD ["sh", "-c", "env > /data/app.log; while true; do echo logging >> /data/app.log; sleep 1; done"]
EOF
In this example, the container image is hosted in the Azure Container Registry, which was provisioned by the Terraform modules for shared resources. You can use any registry as long as you can push images to it, and the cluster has access to pull images from it.
$ export CONTAINER_IMAGE="${AZURE_REGISTRY_NAME}.azurecr.io/env"
$ docker build . -t "${CONTAINER_IMAGE}"
$ docker push "${CONTAINER_IMAGE}"
Build the Confidential Pod image
In the following sections, you will build and measure a VM disk image for your Confidential Pod. The Confidential Pod will run in an Azure Confidential VM (CVM). In Microsoft Azure, launching a new CVM requires creating and storing a VM disk.
Creating and storing VM disks in Azure requires a few extra resources, such as a storage container, an image definition, and an image version. The following sections will guide you step by step in this process.
Before creating the needed resources, generate a random suffix that will be used to ensure that resource names are unique. It also helps to quickly identify related resources (i.e., if they share the same suffix):
$ export SUFFIX="${RANDOM}"
Create a storage container
Before building the Confidential Pod image, create a storage container to store the measured disk image.
$ export AZURE_STORAGE_CONTAINER="env-${SUFFIX}"
$ az storage container create \
--name "${AZURE_STORAGE_CONTAINER}" \
--account-name "${AZURE_STORAGE_ACC_NAME}" \
--resource-group "${AZURE_RESOURCE_GROUP}"
Create an image definition
Create a new image definition within an Azure Compute Gallery. The commands below create a new image definition for your Confidential Pod image.
$ export AZURE_IMAGE_DEFINITION="env-${SUFFIX}"
$ az sig image-definition create \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--gallery-name "${AZURE_GALLERY_NAME}" \
--gallery-image-definition "${AZURE_IMAGE_DEFINITION}" \
--publisher Anjuna \
--offer CVMGA \
--os-type Linux \
--sku AnjGALinuxEnv \
--os-state specialized \
--features SecurityType=ConfidentialVMSupported \
--hyper-v-generation V2 \
--architecture x64
Every time you build and upload a measured VM disk for this image definition, a new "version" of the image definition will be created.
Build and upload the Confidential Pod image
Before building the Confidential Pod image, create a Confidential Pod Configuration file.
The configuration file env-cpod-config.yaml below does the following:
-
Sets the value of the environment variable
DB_USERNAMEtouser. -
Allows the environment variable
LOG_LEVELto be set in the Pod specification. -
Defines a shared, in-memory empty directory named
data. -
Runs a
logshippercontainer that tails the log file that the mainenvcontainer writes to the shared directory.
The env container writes its logs to /data/app.log,
and the logshipper container mounts the same data empty directory
and tails that file, re-emitting each line on its own standard output.
Because the empty directory is backed by memory,
it is a convenient place for containers to exchange data
without writing it to the worker Node’s disk.
This example illustrates how multiple containers in a Confidential Pod can share data
securely through an empty directory.
Refer to the Configuration reference to learn more about the Confidential Pod Configuration file and all the features that it supports. In particular, see Empty directories for details on sharing data between containers.
$ cd "${WORKSPACE}"
$ cat > env-cpod-config.yaml <<EOF
pod:
emptyDirs:
- name: data
containers:
- name: env # This should match the name of the container in the Pod/Deployment.
image: "${CONTAINER_IMAGE}:latest"
env:
- name: DB_USERNAME
value: user
untrusted:
env:
allow:
- LOG_LEVEL
emptyDirMounts:
- name: data
mountPath: /data
- name: logshipper # tails the log file written by the env container
image: docker.io/library/alpine:latest
command: ["sh", "-c", "tail -F /data/app.log"]
emptyDirMounts:
- name: data
mountPath: /data
EOF
To build the Confidential Pod image, run the following command:
In the command below,
you must always specify the fully-qualified container image reference,
i.e., including the registry, the repository, and a tag, as in <registry>/<repository>:<tag>.
|
$ docker load -i ${WORKSPACE}/anjuna-k8s-sev-services-image.tar
$ ./anjuna-k8s-cli/anjuna-k8s-cli build azure \
--disk-size 2G \
--cpod-config env-cpod-config.yaml
Upload your CVM disk to Azure to create a new image version (0.0.1) for the image definition that you created earlier.
$ anjuna-azure-cli disk upload \
--disk disk.vhd \
--image-name env-disk.vhd \
--storage-account "${AZURE_STORAGE_ACC_NAME}" \
--storage-container "${AZURE_STORAGE_CONTAINER}" \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--image-gallery "${AZURE_GALLERY_NAME}" \
--image-definition "${AZURE_IMAGE_DEFINITION}" \
--image-version 0.0.1 \
--location "${AZURE_LOCATION}" \
--subscription-id "${AZURE_SUBSCRIPTION_ID}"
Finally, retrieve the image ID, which will be used in your Pod specification when deploying the confidential workload to Kubernetes.
$ export AZURE_IMAGE_ID=$(az sig image-version show \
-i "${AZURE_IMAGE_DEFINITION}" \
-e 0.0.1 \
-r "${AZURE_GALLERY_NAME}" \
-g "${AZURE_RESOURCE_GROUP}" \
--subscription "${AZURE_SUBSCRIPTION_ID}" \
--query id | tr -d '"')
Once you have the image ID exported to your environment, you are ready to deploy your application as a Confidential Pod, as shown in the next section of this guide.