Home Containers
Containers
Cancel

Containers

Learning Outcomes

  • distinguish between a container and a virtual machine
  • create a container
  • mount a volume
  • map a port
  • list and remove containers
  • create an image
  • remove an image

Resources

Lab

Video walkthrough of this lab.

Creating a Container

Start the Google Cloud Shell.

In the terminal, run the following command:

docker run --rm -it alpine

docker is the Docker client program.

run is the subcommand used create a new container.

--rm is the option to remove the container when it exits.

-i or --interactive keeps STDIN open even if not attached.

-t or --tty allocates a pseudo-TTY. -i and -t are used together to create a container that we can interact with directly from the terminal.

alpine is the name of image upon which the new container is based.

If everything works, you should see a # shell prompt and should be able to use most basic shell commands such as cd, ls, cat, cp, touch, echo, rm, mv and rmdir.

Try the following:

cd /root
echo "Hello!" > first-file.txt
ls -la
cat first-file.txt

Getting Information About Running Containers

Create a new terminal on the host.

Start another container:

docker run --rm -it alpine

Is first-file.txt present in the /root directory in this container?

Create yet another terminal on the host. Run the following command (ON THE HOST – not on the containers) to list the running containers:

docker ps -s

Run the following command to get streaming information on the running containers:

docker stats

You will have to hit Ctrl-C to stop docker stats.

Stop one of the contianers by entering Ctrl-D or exit on its terminal.

Confirm that the container has stopped by using docker ps or docker stats.

Stop the other container.

Where is first-file.txt now?

Working with Images

You can get a list of locally available images using the following command:

docker images

If you are running out of disk space on your host, you can remove images that you are no longer using as follows:

docker rmi cc0abc535e36

Here, cc0abc535e36 is the image ID for the particular image we want to remove.

Mounting Volumes

Frequently we will have a directory of preexisting files that we would like to access inside the container or we end up creating files inside the container that we want to persist beyond the lifetime of the container. In this case, we can use the -v option to docker run to make a directory on the host available inside the container. The value of the -v option has the following form: /path/on/host:/path/inside/container. For example, run following commands on the host:

mkdir site1
cd site1
echo '<h1>First Page!</h1>' > index.html
docker run --rm -it -v $PWD:/mnt/site1 -u 1000:1000 alpine

Inside the container do the following:

cd /mnt/site1
cat index.html
echo '<h1>Second Page</h1>' > page2.html

and then exit the container. What is contained in the current directory on the host now?

Mapping Ports

As with volumes, we often want to make network services running inside the container accessible outside the container. In this case, we use the -p option to docker run to map a port on the host to a port inside the container. For example:

docker run --rm -d -v $PWD:/usr/share/nginx/html:ro -p 8080:80 nginx:alpine

Notice the use of the -d flag instead of -it. -d stands for daemon. This container runs in the background and we do not interact with it directly with the terminal.

The -p flag is used to forward ports on the host to a port inside the container. In this case we are forwarding port 8080 on the host to port 80 insided the container. The Google Cloud Shell allows as to view the app running on port 8080 by clicking on the “Web Preview” icon at the top right of the Cloud Shell window. if you do this, you should see the index.html page you created above. If you edit the address to https://{your domain}/page2.html, you should see page2.html.

Because this container is running in the background, in order to stop it you would need to use the docker stop xxx command where xxx is either the name or ID of the container which you could get from the docker ps command.

Creating Images

Up until this point, we’ve used existing images from the Docker hub registry. There are situations in which we would like to define our own images. For example, what if we wanted to make the simple two page website above a standalone container instead of having to mount the directory with the website files inside the container?

Inside the site1 directory, create a Dockerfile with the following contents:

FROM nginx:alpine

COPY . /usr/share/nginx/html

The FROM clause identifies the base image, in this case the base Alpine image with Nginx installed.

The COPY clause copies everything from the current directory (‘.’) (index.html and page2.html) into the /usr/share/nginx/html directory.

To build the image, run the following command from inside the site1 directory:

docker build -t mywebsite .

The -t option identifies the tag for the image. The ‘.’ argument identifies the directory containing the Dockerfile to build from. In this case, the current directory. We now have self-contained container image that has all the files for the website.

Start up the container as follows:

docker run --rm -d -p 8080:80 mywebsite

Clicking on the “Web Preview” button should show the website. Visit the index.html page and page2.html to confirm that everything is working.

Stop the container using the docker stop xxx command.

Pushing Images to a Container registry

In the Google Cloud Shell environment, we will lose any images we have built when we exit the shell. If we want a persistent copy of an image, we can push it to a container registry.

The first thing we have to do is tag the image identifying the registry:

docker tag mywebsite gcr.io/PROJECT-ID/mywebsite

You will have to replace PROJECT-ID with your actual project ID.

Use the docker images command to verify that the image that the image got tagged correctly.

Before you can push to the Google Container Registry, you have to enable the container registry API. In the Google Cloud console dashboard, go to “TOOLS | Container Registry”. If the API is not already enabled, there should be a button to enable the API that you can click.

You can then push your image to the container registry as follows:

docker push gcr.io/PROJECT-ID/mywebsite

Pulling Images from a Container Registry

You can pull images from a container registry to use local.

To convince yourself that this will work, first delete the local copies of your images as follows:

docker rmi mywebsite gcr.io/PROJECT-ID/mywebsite

Then pull a copy from the container registry as follows:

docker pull gcr.io/PROJECT-ID/mywebsite

You can use the docker images command to verify that a local copy is available.

You can test it out as follows:

docker run --rm -d -p 8080:80 gcr.io/PROJECT-ID/mywebsite

and then preview the web pages as before.

Stop the container when you are finishd using the docker stop xxx command.

Deploying a Container to Compute Engine

Running the container in the Cloud Shell environment is fine for development but only you can access it and only while the shell is running. To make your web application available to the public, it has to be deployed somewhere. We can deploy a container to a Compute Engine VM

In the myapp directory, create a Dockerfile so we can package up the application as a container image:

# Use the official lightweight Node.js 12 image.
# https://hub.docker.com/_/node
FROM node:12-alpine

# Create and change to the app directory.
WORKDIR /usr/src/app

# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm install on every code change.
COPY package*.json ./

# Install production dependencies.
RUN npm install --only=production

# Copy local code to the container image.
COPY . ./

# Run the web service on container startup.
CMD [ "npm", "start" ]

Create a .dockerignore file to exclude files from your container image:

Dockerfile
README.md
node_modules
npm-debug.log

Build and tag the image:

cd ~/myapp
docker build -t gcr.io/PROJECT-ID/myapp .

You can run the image in a container and test it using “Web Preview”:

docker run --rm --env PORT=8080 -it -p 8080:8080 gcr.io/PROJECT-ID/myapp

When you are satisfied the app is working, you can stop it using CTRL-C.

Push the image to the container registry:

docker push gcr.io/PROJECT-ID/myapp

You can deploy the container image to Compute Engine as follows:

  1. Go to “COMPUTE | Compute Engine | VM Instances”
  2. Click on the button to create a new instance.
  3. For “Name”, enter “myapp-container”.
  4. Set region and machine configuration as usual (1 vCPU / 1 GB).
  5. For “Container”, check “Deploy a container image to this VM instance”.
  6. For “Container image”, enter “gcr.io/PROJECT-ID/myapp”.
  7. Expand “Advanced container options”.
  8. Under “Environment variables”, add “PORT” “8080”.
  9. Expand “Management, security, disk, networking, sole tenanacy”.
  10. Click on the “Networking” tab.
  11. For “Network tags”, enter “http-server-8080”.
  12. Click on the “Create” button.
  13. Test the application in a new browser tab.

Assignment

Stage, commit, and push your changes to your “myapp” GitLab project. It will be cloned by your instructor.