4

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.

Blair Nangle
  • 1,221
  • 12
  • 18
  • Did you find a solution to this? I am also trying to take a 2-step process like you but no luck. I am wondering why does Terraform/GCE allow creating a VM without container argument, if eventually we cannot attach a new container. – dev Aug 06 '22 at 10:59
  • 1
    Nope, not yet! Although I haven't spent much time working with GCE lately. – Blair Nangle Aug 07 '22 at 09:12

1 Answers1

1

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

  • Thanks for your answer. I want to be able to decouple my (containerized) app deployment from my infrastructure provisioning. This feels like a reasonable ask of GCP. Also, I may want to deploy an image tagged with a particular SemVer number, rather than `latest` every time, for the purposes of being more explicit about which versions of app code/libraries are running at any instant. To me, my Terraform code should be ignorant of the app version that is running. – Blair Nangle Nov 15 '21 at 16:52
  • There are a couple of options within Google Cloud Platform that allow you to do precisely that. Here you can take a look at the Serverless Computing options [1], or for more complex deployments, you can take a look at the GKE (Google Kubernetes Engine) service that allows you to deploy your containerized applications with a great deal of flexibility as you want [2]. In both options Google does the infrastructure provisioning under the hood and is separated from your GCE (Compute Engine) infrastructure. [1] https://cloud.google.com/serverless [2] https://cloud.google.com/kubernetes-engine – Gabriel Robledo Ahumada Nov 16 '21 at 17:37
  • I don't want to use Kubernetes or some sort of serverless abstraction. I just want to provision a GCE instance with container-optimized OS *without* actually having to specify a container image. This doesn't feel like a crazy thing to expect from GCP, but perhaps I am wrong. – Blair Nangle Nov 16 '21 at 17:49
  • @BlairNangle - You can achieve your goals using Compute Engine + Docker. Container OS is meant to be locked down. It is too locked down for your use case. – John Hanley Aug 07 '22 at 09:48