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 stored in the Docker Artifact Registry of Google Cloud, identified by the environment variable ANJ_IMAGE_REGISTRY and path ANJ_IMAGE_PATH.

$ export CONTAINER_IMAGE="${ANJ_IMAGE_REGISTRY}/${ANJ_IMAGE_PATH}/env"
$ docker build . -t "${CONTAINER_IMAGE}"
$ docker push "${CONTAINER_IMAGE}"

Build the Confidential Pod image

Building a Confidential Pod image builds and measures a VM disk image that contains your target application. Creating and storing VM disks in Google Cloud requires a storage bucket. 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 bucket

Before building the Confidential Pod image, create a storage bucket to store the measured disk image.

$ export GCP_STORAGE_BUCKET="env-${SUFFIX}"
$ gcloud storage buckets create gs://${GCP_STORAGE_BUCKET}

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_USERNAME to user.

  • Allows the environment variable LOG_LEVEL to be set in the Pod specification.

  • Defines a shared, in-memory empty directory named data.

  • Runs a logshipper container that tails the log file that the main env container 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.

$ 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>.
$ ${ANJ_K8S_TOOLSET_DIR}/anjuna-k8s-cli/anjuna-k8s-cli build gcp \
  --disk-size 2G \
  --cpod-config env-cpod-config.yaml

Once the image is built, upload it to the Google Cloud bucket you created previously. Notice that a suffix is used in the image name to differentiate between versions. Make sure to change the version number on subsequent uploads, because the command will fail if the version number already exists.

$ VERSION=0001
$ export ANJUNA_ENV_IMAGE_NAME=env-image-${VERSION}
$ anjuna-gcp-cli disk upload \
  --bucket ${GCP_STORAGE_BUCKET} \
  --disk disk.raw \
  --image ${ANJUNA_ENV_IMAGE_NAME}

Note the ANJUNA_ENV_IMAGE_NAME variable exported here. It will be used when configuring the Kubernetes Deployment manifest on the next page of this guide to deploy the env-image-${VERSION} as an Confidential Pod.