Simple Docker Containers

DockerDockerBeginner
Practice Now

This tutorial is from open-source community. Access the source code

Introduction

In this lab, we will look at some basic Docker commands and a simple build-ship-run workflow. We'll start by running some simple containers, then we'll use a Dockerfile to build a custom app. Finally, we'll look at how to use bind mounts to modify a running container as you might if you were actively developing using Docker.

Prerequisites

You will need all of the following to complete this lab:

  • A clone of the lab's GitHub repo.
  • A DockerID.

Run some simple Docker containers

There are different ways to use containers. These include:

  1. To run a single task: This could be a shell script or a custom app.
  2. Interactively: This connects you to the container similar to the way you SSH into a remote server.
  3. In the background: For long-running services like websites and databases.

In this lab, you'll try each of those options and see how Docker manages the workload.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("`Docker`")) -.-> docker/ContainerOperationsGroup(["`Container Operations`"]) git(("`Git`")) -.-> git/SetupandConfigGroup(["`Setup and Config`"]) docker(("`Docker`")) -.-> docker/DockerfileGroup(["`Dockerfile`"]) docker/ContainerOperationsGroup -.-> docker/exec("`Execute Command in Container`") docker/ContainerOperationsGroup -.-> docker/logs("`View Container Logs`") docker/ContainerOperationsGroup -.-> docker/ps("`List Running Containers`") docker/ContainerOperationsGroup -.-> docker/run("`Run a Container`") git/SetupandConfigGroup -.-> git/clone("`Clone Repo`") docker/ContainerOperationsGroup -.-> docker/top("`Display Running Processes in Container`") docker/DockerfileGroup -.-> docker/build("`Build Image from Dockerfile`") subgraph Lab Skills docker/exec -.-> lab-389188{{"`Simple Docker Containers`"}} docker/logs -.-> lab-389188{{"`Simple Docker Containers`"}} docker/ps -.-> lab-389188{{"`Simple Docker Containers`"}} docker/run -.-> lab-389188{{"`Simple Docker Containers`"}} git/clone -.-> lab-389188{{"`Simple Docker Containers`"}} docker/top -.-> lab-389188{{"`Simple Docker Containers`"}} docker/build -.-> lab-389188{{"`Simple Docker Containers`"}} end

Clone the Lab's GitHub Repo

Use the following command to clone the lab's repo from GitHub (you can click the command or manually type it). This will make a copy of the lab's repo in a new sub-directory called linux_tweet_app at /home/labex/project path.

cd /home/labex/project
git clone https://github.com/dockersamples/linux_tweet_app

Run a Single Task in an Alpine Linux Container

In this step we're going to start a new container and tell it to run the hostname command. The container will start, execute the hostname command, then exit.

  1. Run the following command in your Linux console.

    docker run alpine hostname

    The output below shows that the alpine:latest image could not be found locally. When this happens, Docker automatically pulls it from Docker Hub.

  2. Docker keeps a container running as long as the process it started inside the container is still running. In this case the hostname process exits as soon as the output is written. This means the container stops. However, Docker doesn't delete resources by default, so the container still exists in the Exited state.

    List all containers.

    docker ps -a

    Notice that your Alpine Linux container is in the Exited state.

    CONTAINER ID   IMAGE                                 COMMAND                  CREATED         STATUS                      PORTS                                                                                                                                  NAMES
    5688b118567b   alpine                                "hostname"               2 minutes ago   Exited (0) 2 minutes ago                                                                                                                                           hopeful_kowalevski

    Note: The container ID is the hostname that the container displayed. In the example above it's 5688b118567b.

Containers which do one task and then exit can be very useful. You could build a Docker image that executes a script to configure something. Anyone can execute that task just by running the container - they don't need the actual scripts or configuration information.

Run an Interactive Ubuntu Container

You can run a container based on a different version of Linux than is running on your Docker host.

In the next example, we are going to run an Ubuntu Linux container on top of an Alpine Linux Docker host (Play With Docker uses Alpine Linux for its nodes).

  1. Run a Docker container and access its shell.

    docker run --interactive --tty --rm ubuntu bash

    In this example, we're giving Docker three parameters:

    • --interactive says you want an interactive session.
    • --tty allocates a pseudo-tty.
    • --rm tells Docker to go ahead and remove the container when it's done executing.

    The first two parameters allow you to interact with the Docker container.

    We're also telling the container to run bash as its main process (PID 1).

    When the container starts you'll drop into the bash shell with the default prompt root@<container id>:/#. Docker has attached to the shell in the container, relaying input and output between your local session and the shell session in the container.

  2. Run the following commands in the container.

    ls / will list the contents of the root directory in the container, ps aux will show running processes in the container, cat /etc/issue will show which Linux distro the container is running, in this case Ubuntu 20.04.3 LTS.

    ls /

    output:

    bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
    ps aux

    output:

    USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
    root 1 0.0 0.1 4628 3892 pts/0 Ss 03:06 0:00 bash
    root 11 0.0 0.0 7060 1668 pts/0 R+ 03:07 0:00 ps aux
    cat /etc/issue

    output:

    Ubuntu 22.04.2 LTS \n \l
  3. Type exit to leave the shell session. This will terminate the bash process, causing the container to exit.

    exit

    Note: As we used the --rm flag when we started the container, Docker removed the container when it stopped. This means if you run another docker ps -a you won't see the Ubuntu container.

Run a Background MySQL Container

Background containers are how you'll run most applications. Here's a simple example using MySQL.

  1. Run a new MySQL container with the following command.

    docker run \
      --detach \
      --name mydb \
      -e MYSQL_ROOT_PASSWORD=my-secret-pw \
      mysql:latest
    • --detach will run the container in the background.
    • --name will name it mydb.
    • -e will use an environment variable to specify the root password (NOTE: This should never be done in production).
  2. List the running containers.

    docker ps

    Notice your container is running.

    CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS          PORTS                 NAMES
    c720e0482ce7   mysql:latest   "docker-entrypoint.sâ€Ķ"   About a minute ago   Up 55 seconds   3306/tcp, 33060/tcp   mydb
  3. You can check what's happening in your containers by using a couple of built-in Docker commands: docker logs and docker top.

    docker logs mydb

    This shows the logs from the MySQL Docker container.

      <output truncated>
      2023-06-20T03:12:49.102168Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
      2023-06-20T03:12:49.122241Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
      2023-06-20T03:12:49.122342Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.33'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

    Let's look at the processes running inside the container.

    docker top mydb

    You should see the MySQL daemon (mysqld) is running in the container.

    UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
    lxd                 4420                4392                0                   10:34               ?                   00:00:00            mysqld

    Although MySQL is running, it is isolated within the container because no network ports have been published to the host. Network traffic cannot reach containers from the host unless ports are explicitly published.

  4. List the MySQL version using docker exec.

    docker exec allows you to run a command inside a container. In this example, we'll use docker container exec to run the command-line equivalent of mysql --user=root --password=$MYSQL_ROOT_PASSWORD --version inside our MySQL container.

    docker exec -it mydb mysql --user=root --password=$MYSQL_ROOT_PASSWORD --version

    You will see the MySQL version number, as well as a handy warning.

    mysql: [Warning] Using a password on the command line interface can be insecure.
    mysql  Ver 8.0.33 for Linux on x86_64 (MySQL Community Server - GPL)
  5. You can also use docker exec to connect to a new shell process inside an already-running container. Executing the command below will give you an interactive shell (sh) inside your MySQL container.

    docker exec -it mydb sh

    Notice that your shell prompt has changed. This is because your shell is now connected to the sh process running inside of your container.

  6. Let's check the version number by running the same command again, only this time from within the new shell session in the container.

    mysql --user=root --password=$MYSQL_ROOT_PASSWORD --version

    Notice the output is the same as before.

  7. Type exit to leave the interactive shell session.

    exit

Package and Run a Custom App Using Docker

In this step you'll learn how to package your own apps as Docker images using a Dockerfile.

The Dockerfile syntax is straightforward. In this task, we're going to create a simple NGINX website from a Dockerfile.

  1. Make sure you're in the linux_tweet_app directory.

    cd /home/labex/project/linux_tweet_app
  2. Display the contents of the Dockerfile.

    cat Dockerfile
    FROM nginx:latest
    
    COPY index.html /usr/share/nginx/html
    COPY linux.png /usr/share/nginx/html
    
    EXPOSE 80 443
    
    CMD ["nginx", "-g", "daemon off;"]

    Let's see what each of these lines in the Dockerfile do.

    • FROM specifies the base image to use as the starting point for this new image you're creating. For this example we're starting from nginx:latest.
    • COPY copies files from the Docker host into the image, at a known location. In this example, COPY is used to copy two files into the image: index.html. and a graphic that will be used on our webpage.
    • EXPOSE documents which ports the application uses.
    • CMD specifies what command to run when a container is started from the image. Notice that we can specify the command, as well as run-time arguments.
  3. In order to make the following commands more copy/paste friendly, export an environment variable containing your DockerID (if you don't have a DockerID you can get one for free via Docker Hub).

    You will have to manually type this command as it requires your unique DockerID.

    export DOCKERID=<your docker id>
  4. Echo the value of the variable back to the terminal to ensure it was stored correctly.

    echo $DOCKERID
  5. Use the docker build command to create a new Docker image using the instructions in the Dockerfile.

    • --tag allows us to give the image a custom name. In this case it's comprised of our DockerID, the application name, and a version. Having the Docker ID attached to the name will allow us to store it on Docker Hub in a later step
    • . tells Docker to use the current directory as the build context

    Be sure to include period (.) at the end of the command.

    docker build --tag $DOCKERID/linux_tweet_app:1.0 .

Summary

Congratulations! You have completed the Docker for Beginners - Linux lab. You can practice more labs in LabEx to improve your skills.

Other Docker Tutorials you may like