Creating and configuring instances

There are two ways to create and configure Compute Engine instances running Container-Optimized OS from Google.

For simple scenarios where you want to run a single container on a VM or on each VM in a managed instance group, you can specify a container image and optional configuration parameters when you define the instance or instance template. Compute Engine creates the instance with the latest version of Container-Optimized OS and launches the specified container when the VM starts.

For advanced scenarios where you can deploy multiple containers and configure Docker options using cloud-init, you can create a Compute Engine instance with your choice of Container-Optimized OS image then proceed to configure it as needed.

Creating a simple instance

Use this method to deploy a single container on a VM using the latest version of Container-Optimized OS. You can perform this task using the Google Cloud console or gcloud CLI.

Console

  1. Go to the VM instances page.

    Go to the VM instances page

  2. Click Create instance.

  3. Specify a Name for your instance.

  4. In the Container section, select the Deploy a container image to this VM instance checkbox.

  5. Specify the Container image to use.

    • You can specify an image from Container Registry or Artifact Registry. For example:
      • gcr.io/cloud-marketplace/google/nginx1:1.15 selects an NGINX 1.15 container image from Google Cloud Marketplace.
      • us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0 selects a sample hello-app image from Artifact Registry.
    • If you use a container image from Docker Hub, always specify the full Docker image name. For example, specify the following image name to deploy an Apache container image: docker.io/httpd:2.4.
  6. Optionally, click Advanced container options. For more information, see Configuring Options to Run Your Container.

  7. Click Create to create the instance, boot the instance, and launch the container.

gcloud

To create a simple VM instance, run the following command:

gcloud compute instances create-with-container instance-name \
    --container-image image-name

Replace the following:

  • instance-name: the name for the new instance.
  • image-name: the name of the container image.

For example, the following command creates a new VM instance named nginx-vm, which will launch and run the gcr.io/cloud-marketplace/google/nginx1:1.15 container image:

gcloud compute instances create-with-container nginx-vm \
    --container-image gcr.io/cloud-marketplace/google/nginx1:1.15

Similarly, you can create a new VM instance named hello-app which will launch and run a sample container in Artifact Registry:

gcloud compute instances create-with-container hello-app \
--container-image us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0

When using a container image from Docker Hub, you must always specify a full Docker image name. For example, specify the following image name to deploy an Apache container image:

docker.io/httpd:2.4

To run a single container on each VM in a managed instance group, specify the container image name when defining the instance template. See Creating an instance template with a container image for more information.

Creating an instance for advanced scenarios

Use this method to select a specific Container-Optimized OS image, to deploy multiple containers, and to use cloud-init for advanced configuration.

Viewing available images

Container-Optimized OS images are available on Google Cloud console's list of images with the prefix cos. These are hosted under the cos-cloud project. You can also see all currently available releases on command line by running the following command:

gcloud compute images list --project cos-cloud --no-standard-images

The output is similar to the following:

NAME                       PROJECT    FAMILY      DEPRECATED  STATUS
cos-69-10895-385-0         cos-cloud  cos-69-lts              READY
cos-73-11647-534-0         cos-cloud  cos-73-lts              READY
cos-77-12371-251-0         cos-cloud  cos-77-lts              READY
cos-81-12871-103-0         cos-cloud  cos-81-lts              READY
cos-beta-81-12871-44-0     cos-cloud  cos-beta                READY
cos-dev-84-13078-0-0       cos-cloud  cos-dev                 READY
cos-stable-81-12871-103-0  cos-cloud  cos-stable              READY

Creating an instance

You can create an instance using the Google Cloud console, gcloud CLI, or the API.

Console

To run a Compute Engine instance with a Container-Optimized OS and Docker installed, perform the following:

  1. Open the Compute Engine instance creation page on Google Cloud console.

    Create a new Compute Engine instance

  2. Specify a Name for your instance.

  3. In the Containers section, clear the Deploy a container image to this VM instance checkbox. This option is useful if you want to deploy a single container on the VM.

  4. In the Boot disk section, select a Container-Optimized OS image.

  5. Click Create to create and boot the instance.

gcloud

Review the currently available images, then use the following command to create a cos node image instance:

gcloud compute instances create instance-name \
    --image image-name \
    --image-project cos-cloud \
    --zone compute-zone \
    --machine-type machine-type-name

Replace the following:

  • instance-name: the name of your VM instance.
  • image-name: the name of the Container-Optimized OS image for the instance, obtained from the list of available images. From our previous example, we can use cos-beta-81-12871-44-0.
  • compute-zone: the compute zone for your instance.
  • machine-type-name: the machine type to use for this new instance. The default type is n1-standard-1.

For example, the following command creates an instanced named cos-test using the cos-beta-67-10575-13-0 image:

gcloud compute instances create cos-test \
    --image cos-beta-67-10575-13-0 \
    --image-project cos-cloud \
    --zone us-east1-d \
    --machine-type n1-standard-1

If you want the latest available dev, beta, or stable Container-Optimized OS, use the --image-family flag, like the following:

gcloud compute instances create instance-name \
    --image-family cos-beta \
    --image-project cos-cloud \
    --zone compute-zone \
    --machine-type machine-type-name

You can add the --preemptible flag for one-off, experimental instances.

API

In the API, construct a normal request to create an instance, but include a Container-Optimized OS source image. For example:

POST https://compute.googleapis.com/compute/v1/projects/project-id/zones/compute-zone/instances

{
  'machineType': 'zones/compute-zone/machineTypes/machine-type-name',
  'name': 'instance-name',
  'networkInterfaces': [
    {
      'accessConfigs': [
        {
          'type': 'ONE_TO_ONE_NAT',
          'name': 'External NAT'
        }
      ],
      'network': 'global/networks/default'
    }
  ],
  'disks': [
    {
      'type': 'PERSISTENT',
      'boot': true,
      'autoDelete': true,
      'initializeParams': {
        'sourceImage': 'projects/cos-cloud/global/images/family/cos-stable'
      }
    }
  ]
}

Configuring an instance

In some cases, you might want to do additional configuration when the instance boots. You can use the cloud-init tool with Container-Optimized OS to apply configuration information that you supply in a cloud-config format.

Using cloud-init with the Cloud config format

Container-Optimized OS images include cloud-init as a way to configure your instance when it boots up. The cloud-init tool expects its configuration in the value of the user-data key of the instance metadata. The cloud-init tool understands multiple formats.

Here's an example cloud-init file showing how to create a user account and create a systemd service owned by this user that controls the management of a Docker busybox container:

#cloud-config

users:
- name: cloudservice
  uid: 2000

write_files:
- path: /etc/systemd/system/cloudservice.service
  permissions: 0644
  owner: root
  content: |
    [Unit]
    Description=Start a simple docker container

    [Service]
    ExecStart=/usr/bin/docker run --rm -u 2000 --name=mycloudservice busybox:latest /bin/sleep 3600
    ExecStop=/usr/bin/docker stop mycloudservice
    ExecStopPost=/usr/bin/docker rm mycloudservice

runcmd:
- systemctl daemon-reload
- systemctl start cloudservice.service

# Optional once-per-boot setup. For example: mounting a PD.
bootcmd:
- fsck.ext4 -tvy /dev/[DEVICE_ID]
- mkdir -p /mnt/disks/[MNT_DIR]
- mount -t ext4 -O ... /dev/[DEVICE_ID] /mnt/disks/[MNT_DIR]

To create a Container-Optimized OS VM instance that references this cloud-init file, use the --metadata-from-file command line flag. Assuming the cloud-init file is called filename in the current directory, the following command creates a Container-Optimized OS instance and trigger cloud-init by assigning the contents of the file to the user-data key in the Instance Metadata:

gcloud compute instances create instance-name \
    --image-family cos-stable \
    --image-project cos-cloud \
    --metadata-from-file user-data=filename

Replace the following:

  • instance-name: the name of your VM instance.
  • filename: the name of the metadata file.

It is possible to set other metadata flags when creating Container-Optimized OS instances. Because these properties are simple key-value pairs, you may use the --metadata flag in the gcloud compute instances create command to create the properties. Also, starting from milestone 97, you can set metadata flags in project metadata using the --metadata flag in the gcloud compute project-info add-metadata command. Flags defined at the instance level will take precedence over flags defined at the project level.

The previous example can be expanded to collect usage statistics and crash dump collection with the following command:

gcloud compute instances create instance-name \
    --image-family cos-stable \
    --image-project cos-cloud \
    --metadata-from-file user-data=filename \
    --metadata=cos-metrics-enabled=true

Other metadata flags

Metadata Key Description Default Behavior
cos-update-strategy Specifies update behavior. The only value accepted is: update_disabled. If not set:
  • cos-dev and cos-beta: Updates from latest OS version in the corresponding image family
  • LTS milestone and cos-stable: Updates from latest OS version from the same milestone
cos-metrics-enabled Enables crash dump collection. Values could be:
true
false (default).
Disabled by default

Connecting to an instance

You can SSH into your VM instance running the cos node image the same way you SSH into other Compute Engine instances.

For example:

gcloud compute ssh instance-name \
    --project project-id \
    --zone compute-zone

Running startup scripts

You can specify a startup script through the metadata server, using the startup-script metadata key. You can use the Google Cloud CLI, the API, or Google Cloud console to provide a startup script. Refer to Running Startup Scripts for details.

Time synchronization

Before milestone 85, Container-Optimized OS uses systemd's systemd-timesyncd service to synchronize the local system clock with a remote Network Time Protocol (NTP) server via the SNTP protocol. The following entries in /etc/systemd/timesyncd.conf configuration file show commented out default configuration values to help the administrator make any desired changes:

cat /etc/systemd/timesyncd.conf
# comments omitted for brevity
[Time]
#NTP=
#FallbackNTP=metadata.google.internal
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048

So the maximum acceptable root distance is 5 seconds and the minimum and maximum poll intervals for NTP messages are 32 and 2048 seconds respectively.

Starting from milestone 85, Container-Optimized OS uses chronyd service to synchronize the local system clock with a remote Network Time Protocol (NTP) server via the NTP protocol. The following entries in the /etc/chrony/chrony.conf configuration file show commented out default configuration values to help the administrator make any desired changes:

cat /etc/chrony/chrony.conf
# Use custom NTP servers
server metadata.google.internal prefer iburst

# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift

# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3

# Enable kernel synchronization of the real-time clock (RTC).
rtcsync

The NTP server is set from eth0's DHCP response, which is usually the Compute Engine's metadata server:

networkctl status eth0 | grep NTP
             NTP: 169.254.169.254

Changing the time zone

The default time zone of Container-Optimized OS from Google is UTC0. Create a symbolic link to your desired time zone as in the following example:

sudo rm /etc/localtime
sudo ln -s /usr/share/zoneinfo/US/Pacific /etc/localtime

Note that /etc is stateless, so the time zone will be reset to the default (UTC0) every reboot.

Disabling automatic updates

There are two ways to disable automatic updates. The preferred method is to use the cos-update-strategy instance metadata key:

gcloud compute instances create instance-name \
    --image-family cos-stable \
    --image-project cos-cloud \
    --metadata cos-update-strategy=update_disabled

Starting from milestone 97, you can also disable automatic updates in project metadata:

gcloud compute project-info add-metadata \
    --metadata cos-update-strategy=update_disabled

You can also disable automatic updates on a running instance with systemctl:

sudo systemctl stop update-engine
sudo systemctl mask update-engine