You can run a Docker container on a machine running Container-Optimized OS in
much the same way as you would on most other node image distributions, by using
the docker run
command. For example:
docker run --rm busybox echo "hello world"
The following output appears:
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
. . .
Status: Downloaded newer image for busybox:latest
hello world
cos
image are added to
the docker
group by default. This lets any logged-in user run docker
commands without root privileges.
Accessing public images in Container Registry or Artifact Registry
Container Registry support is built in to the cos
node image. To
start a container from Container Registry, run:
docker run --rm gcr.io/google-containers/busybox echo "hello world"
The following output appears:
Unable to find image 'gcr.io/google-containers/busybox:latest' locally
Pulling repository gcr.io/google-containers/busybox
. . .
Status: Downloaded newer image for gcr.io/google-containers/busybox:latest
hello world
Accessing private images in Artifact Registry or Container Registry
Starting with milestone 60 releases,
docker-credential-gcr
is pre-installed in Container-Optimized OS images. It's the recommended
way to access private images in Artifact Registry or Container Registry.
To use docker-credential-gcr
, run the following command:
Artifact Registry
docker-credential-gcr configure-docker --registries LOCATION-docker.pkg.dev
Replace LOCATION with the location of your repository.
Container Registry
docker-credential-gcr configure-docker
The following output appears:
/home/username/.docker/config.json configured to use this credential helper
To run an image from the registry, use the following command:
Artifact Registry
docker run --rm LOCATION-docker.pkg.dev/your-project/repository/your-image
Replace LOCATION with the location of your repository.
Container Registry
docker run --rm gcr.io/your-project/your-image
You can use the following Container Registry hostnames:
- us.gcr.io
- eu.gcr.io
- asia.gcr.io
To use docker with sudo
, run the following command. The -E
command-line
flag makes docker use the .docker/config.json
file from a user's home
directory instead of the root home directory.
Artifact Registry
sudo -E docker run --rm LOCATION-docker.pkg.dev/your-project/repository/your-image
Replace LOCATION with the location of your repository.
Container Registry
sudo -E docker run --rm gcr.io/your-project/your-image
Supported Container Registry hostnames are:
- us.gcr.io
- eu.gcr.io
- asia.gcr.io
Alternately, you can fetch appropriate OAuth access tokens from Compute Engine
metadata and use them with the docker login
command manually, as shown in the
following example:
METADATA=http://metadata.google.internal/computeMetadata/v1
SVC_ACCT=$METADATA/instance/service-accounts/default
ACCESS_TOKEN=$(curl -H 'Metadata-Flavor: Google' $SVC_ACCT/token | cut -d'"' -f 4)
docker login -u oauth2accesstoken -p $ACCESS_TOKEN https://gcr.io
docker run … gcr.io/your-project/your-image
Using cloud-init with Container Registry
This cloud-init example uses the Cloud Config format to start a Docker container from an image stored in Docker's container registry called DockerHub. The example below uses the Cloud Config format to start a Docker container from an image stored in Container Registry:
#cloud-config
write_files:
- path: /etc/systemd/system/cloudservice.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Start a simple docker container
Wants=gcr-online.target
After=gcr-online.target
[Service]
Environment="HOME=/home/cloudservice"
ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
ExecStart=/usr/bin/docker run --rm --name=mycloudservice gcr.io/google-containers/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
Configuring Docker daemon to pull images from registry cache
You can configure Docker daemon to pull images from a registry cache by using registry mirrors.
Configure the daemon to use the
registry-mirror
option in one of the following ways:- In the
/etc/default/docker
file, add theregistry-mirror
option for the registry (for example,https://mirror.gcr.io
):
echo 'DOCKER_OPTS="--registry-mirror=https://mirror.gcr.io"' | tee /etc/default/docker
- In the
/etc/default/docker
file, append"--registry-mirror=https://mirror.gcr.io"
to the existingDOCKER_OPTS
:
sed -i -e 's|"$| --registry-mirror=https://mirror.gcr.io"|' /etc/default/docker
- In the
After adding the registry mirror, restart the Docker daemon for the changes to take effect:
sudo systemctl daemon-reload sudo systemctl restart docker
Adding a configuration to /etc/default/docker
is non-persistent across reboot.
To ensure that your docker configuration remains persistent across reboots,
consider adding the commands either in the cloud-init
script of the instance's
metadata in the cloud-config
format
or startup script
.
The following example uses the cloud-config
format to configure a
registry-mirror
:
#cloud-config
runcmd:
- echo 'DOCKER_OPTS="--registry-mirror=https://mirror.gcr.io"' | tee /etc/default/docker
- systemctl daemon-reload
- systemctl restart docker
For more on configuring an instance with cloud-init
, see
Using cloud-init with the Cloud config format.
Troubleshooting
Resolving option conflicts between Docker daemon.json
and flags
When configuring the Docker daemon, if the same option is set with a
daemon.json
file and with flags, Docker will fail to start with an error
similar to:
unable to configure the Docker daemon with file /etc/docker/daemon.json:
the following directives are specified both as a flag and in the configuration file:
The recommended solution to resolve this conflict is to modify the default
daemon.json
, which is located at /etc/docker/daemon.json
. Modifying this
file allows for changing only the affected options, while maintaining the other
default options. This can be done using cloud-init
, for example using a
cloud-config
similar to:
#cloud-config
write_files:
- path: /tmp/modify_docker_daemon_opts.py
permissions: 0744
owner: root
content: |
import json, sys, os, logging
DAEMON_OPTS_FILE = '/etc/docker/daemon.json'
opts = {}
if os.path.exists(DAEMON_OPTS_FILE):
with open(DAEMON_OPTS_FILE) as f:
try:
opts = json.load(f)
except:
logging.info("json parsing failed, starting with empty config.")
pass
# Add your daemon option modifications here
# For example,
# opts['log-opts']['max-size'] = '100m'
with open(DAEMON_OPTS_FILE, 'w') as f:
json.dump(opts, f)
runcmd:
- python /tmp/modify_docker_daemon_opts.py
- rm -f /tmp/modify_docker_daemon_opts.py
- systemctl restart docker.service