Is it possible to provision a container-optimised OS VM on GCE without actually deploying an image?

Viewed 600

I want to build a CI pipeline where the infrastructure stage provisions with Terraform a container-optimised operating system instance on Google Compute Engine before the Dockerized application is uploaded to Artifact Registry and deployed for the first time.

My Terraform config:

data "google_compute_image" "cos" {
  family  = "cos-stable"
  project = "cos-cloud"
}

resource "google_compute_instance" "container_optimized_os_vm" {
  name                      = "container-optimized-os-vm"
  machine_type              = "f1-micro"
  allow_stopping_for_update = true

  network_interface {
    network = "default"
  }

  boot_disk {
    initialize_params {
      image = data.google_compute_image.cos.self_link
    }
  }

  metadata = {
    google-logging-enabled = "true"
    gce-container-declaration =<<EOT
spec:
  containers:
    - image: image-repository/image-name:latest
      name: containervm
      securityContext:
        privileged: false
      stdin: false
      tty: false
      volumeMounts: []
      restartPolicy: Always
      volumes: []
EOT
  }
}

My command to deploy the latest version of my image from Artifact Registry:

gcloud compute instances update-container container-optimized-os-vm \
            --zone europe-west2-b \
            --container-image "europe-west2-docker.pkg.dev/my-project-id/my-image-repository-name/my-image-name:latest"

When I omit the gce-container-declaration metadata, I get the following error:

ERROR: (gcloud.compute.instances.update-container) Instance doesn't have gce-container-declaration metadata key - it is not a container.

I want to be able to provision the instance without specifying an image in gce-container-declaration—is this possible? My worry is that when infrastructure changes are detected, the image in gce-container-declaration will be deployed instead of my application's image.

1 Answers

Just to be clear, the container optimized OS is used for running Docker containers, it means that your VM instance is created as a Docker container and your containerized application will run on top of it, as stated in the following documentation [1].

Now, the gce-container-declaration argument is the manifest of your container, and in which you can specify all the arguments you want for your containerized application (including the image).

Running the command gcloud compute instances update-container with your application image path as the --container-image flag only changes the original container image deployed from image-repository/image-name:latest to europe-west2-docker.pkg.dev/my-project-id/my-image-repository-name/my-image-name:latest, same that you could have specified in the first place:

 metadata = {
    google-logging-enabled = "true"
    gce-container-declaration =<<EOT
spec:
  containers:
    - image: europe-west2-docker.pkg.dev/my-project-id/my-image-repository-name/my-image-name:latest
      name: containervm
      securityContext:
        privileged: false
      stdin: false
      tty: false
      volumeMounts: []
      restartPolicy: Always
      volumes: []
EOT
  }

The error you are getting is because once you take out the gce-container-declaration flag the VM instance is no longer created as a container but just a normal VM; hence the error.

I do not see why you want to create the VM instance to later deploy your application when both can be done in parallel, and actually the terraform code provided works that way.

[1] https://cloud.google.com/container-optimized-os/docs/concepts/features-and-benefits

Related