Skip to content

Instantly share code, notes, and snippets.

@jtgasper3
Last active June 27, 2019 21:09
Show Gist options
  • Save jtgasper3/e55855f7dc5ef11a687feae6495c904d to your computer and use it in GitHub Desktop.
Save jtgasper3/e55855f7dc5ef11a687feae6495c904d to your computer and use it in GitHub Desktop.
Docker Training Labs

Hello World

Objective: This is a basic container used to ensure that Docker is installed and working.

  1. Run the container: docker container run -it hello-world

    -it allows the terminal to send and receive text to/from the container.

This should have returned some text.

Docker Hub

Objective: To familiarize ones self with Docker Hub, searching for images, etc.

  1. Go to https://hub.docker.com.

  2. Search for an application you are interested in. Some suggestions might include httpd, mariadb, mysql, or redmine.

  3. Does the image appear to come from a reputable source? Is it an automated build? Is there a link to the GitHub source?

  4. Examine the readme. Is there enough documentation for you to run the aplication?

  5. What tags are available for the image?

Containers

Objective: To become with familiar with the docker container subset of commands.

  1. Show a list of running containers: docker container ps

  2. Show a list of all containers: docker container ps -a

  3. Start a dettached container from one you identified in the last exercise: docker container run -d <imageName>

  4. List the running containers: docker container ps

  5. Connect to (terminal into) the container container: docker container exec -it <containerIdOrName> bash

  6. List the processes running within the container: ps aux

  7. Feel free to look around the container's file system: ls

  8. Exit the container: exit

  9. Did the container produce any logs?: docker container logs <containerIdOrName>

  10. Stop the container: docker container stop <containerIdOrName>

  11. Delete the container: docker container rm <containerIdOrName>

Images

Building our first image

Objective: To build and run an image using Dockerfile.

  1. Create a directory for your project.

  2. In the directory create a file called Dockerfile with the following contents:

    FROM httpd
    
    COPY website/ /usr/local/apache2/htdocs/
  3. Create a sub directory named website.

  4. Create an HTML file in the website directory called index.html.

  5. Populate index.html with any contents you would like to use, or use something like the following:

    <html>
      <head>
        <title>Docker Class</title>
      </head>
      <body>
        Docker is the coolest!!
      </body>
    </html>
  6. Build the image giving it a name of class: docker image build --tag=class:v1 .

  7. Try running your image (giving it a name myweb): docker container run -d -p 80:80 --name myweb class:v1

    -d starts the container detached, as a background process.

    -p maps a host networking port to the container's port.

  8. Can you access your page at http://localhost/?

  9. Stop your container: docker container stop myweb

  10. Refresh your website's page in the browser. Does it work?

    You should not be able to as the container/process is stop.

  11. Remove the container: docker container rm myweb

Updating our image

Objective: To see how image tagging works.

  1. Update index.html with any content changes that you would like, or use something like the following:

    <html>
      <head>
        <title>Docker Class</title>
      </head>
      <body>
        <h1>Docker is the coolest!!</h1>
    
        <p>I have the best instructor ever.</p>
      </body>
    </html>
  2. Build the image changing the image's tag: docker image build --tag=class:v2 .

  3. Try running your image (giving it a name myweb): docker container run -d -p 80:80 --name myweb class:v2

  4. Can you access your updated page at http://localhost/?

  5. Stop and remove the container.

Looking at images

Objective to use the docker image subset of commands.

  1. Review the list of images on your host: docker image ls

    If the list is too long try; docker image ls class

  2. What layers are apart of your image: docker image history class:v2

  3. Remove the first version of our class image: docker image rm class:v1

Mounts & Volumes

Using Volumes

Objective: Using our website created in the last set of exercises, understand the basics of working with Docker Volumes.

  1. Create a volume: docker volume create website

  2. Modify our website's Dockerfile by adding a command some where after the FROM line: VOLUME /usr/local/apache2/htdocs/

  3. Rebuild the image (feel free to re-use the tag... or use a different tag, but be sure to use this new tag in the next command).

  4. Start the image: docker container run -d -p 80:80 --name myweb --mount source=website,target=/usr/local/apache2/htdocs/ class:v3

  5. When browsing your page, it should be the same as before.

  6. Stop and remove the container.

  7. Now, change the webpage in some noticable way.

  8. Rebuild and redeploy your application using the new image. Which page is being used?

  9. Stop and remove the container.

  10. Delete the volume (docker volume rm website) and recreate it.

  11. Create a new container using the volume. Which page is being used?

If a volume is new, Docker will copy any data container volume path(s) at startup into the new volume.

Mounting a Host Directory

Objective: To understand the basics of working with bind mounts.

  1. Create a new HTML file called index.html, but not in our website/ directory.

  2. (Stop and remove any previously running containers.)

  3. Start a new container mounting in the host system's directory where our new html file exists: docker container run -d -p 80:80 --name myweb --mount type=bind,source=$(pwd),target=/usr/local/apache2/htdocs/test/ class:v3

    The source value must be fully qualified. On a Mac or Linux, $(pwd) will evaluate to the fully qualified path of the directory the command is executed from.

  4. Browse to http://localhost/test/.

  5. Stop the container: docker container stop myweb

  6. Change the new HTML file.

  7. Start the container: docker container start myweb

  8. Refresh the webpage.

Networking

Objective: To understand the basics of working with Docker Networks by running a WordPress container connected to a MySQL DB container.

  1. Start a MySQL container:

    docker container run -d --name mysql \
      -e MYSQL_ROOT_PASSWORD=secret \
      -e MYSQL_DATABASE=wordpress \
      -e MYSQL_USER=wordpress \
      -e MYSQL_PASSWORD=wordpress \
      mysql:5.7

    -e injects an environment variable into the container at start-up.

  2. Start a WordPress container:

    docker container run -d \
      --name wordpress \
      -e WORDPRESS_DB_HOST=mysql:3306 \
      -e WORDPRESS_DB_USER=wordpress \
      -e WORDPRESS_DB_PASSWORD=wordpress \
      -e WORDPRESS_DB_NAME=wordpress \
      -p 80:80 \
      wordpress
  3. Browse to http://localhost

    Did this work? Probably not. Why not?

  4. What do the logs say?: docker logs wordpress

    There is no route to the MySQL container from the WordPress container. We need to stop the containers (docker container rm -f mysql wordpress) and place new instances on the same network.

  5. List out the existing (software defined networks) in Docker: docker network ls

  6. Create a dedicated network for our containers: docker network create -d bridge wordpress-nw

    -d (or --driver) specifies which network driver to use when creating the network.

  7. What subnet will the containers be on? docker network inspect wordpress-nw

  8. Start a MySQL container:

    docker run -d \
      --name mysql \
      --network=wordpress-nw \
      -e MYSQL_ROOT_PASSWORD=secret \
      -e MYSQL_DATABASE=wordpress \
      -e MYSQL_USER=wordpress \
      -e MYSQL_PASSWORD=wordpress \
      mysql:5.7
  9. Start a WordPress container:

    docker container run -d \
       --name wordpress \
       -e WORDPRESS_DB_HOST=mysql:3306 \
       -e WORDPRESS_DB_USER=wordpress \
       -e WORDPRESS_DB_PASSWORD=wordpress \
       -e WORDPRESS_DB_NAME=wordpress \
       --network=wordpress-nw \
       -p 80:80 \
       wordpress
  10. Browse to http://localhost

  11. Check out the network information now: docker network inspect wordpress-nw

Reset the environment with:

docker rm -f wordpress mysql
docker network rm wordpress-nw

-f forces the rm operation.

Docker-Compose

Objective: To see how the Docker Compose tool works.

  1. Create a fle named docker-compose.yml with the following contents:
version: '3.3'

services:
   mysql:
     image: mysql:5.7
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     image: wordpress:latest
     ports:
       - "80:80"
     environment:
       WORDPRESS_DB_HOST: mysql:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
       WORDPRESS_DB_NAME: wordpress
  1. Start the containers docker-compose up

  2. Trying browsing to http://localhost.

  3. Ctrl+C will stop the containers. Use docker-compose up -d to run the containers in a detached manner.

  4. Clean-up things up with : docker-compose down -v

    -v removes any volumes associated with the compose file/containers.

Docker Swarm

We have started a "polling" company. Our developers have packaged our soluion as a set of Docker images. We need to deploy their solution in short order, and we need to do it in a way that we can scale it quickly.

The solution consists of two web applications, a database, a redis cache, a worker application, and a monitoring application. Our website launches tonight! So get busy!

To run this exercise, it is recommended that you use https://labs.play-with-docker.com. PWD allows the user to spin up multiple Docker hosts to allow us to create a nicely sized Swarm. PWD (and some of the exercises) tend to run better with Chrome.

Cats vs Dogs Version 1

Objective: To create a swarm and deploy an application stack to the swarm.

  1. After creating the first instance, create a swarm: docker swarm init --advertise-addr=<IP>. Change the <IP> to that listed in the prompt.

    Note the command outputted by this command.

  2. Create a second host instance by copying the command outputted from the swarm init command, and run it in the second instance.

  3. On the first instance, run docker node ls

  4. Clone the voting app project: git clone https://github.com/dockersamples/example-voting-app.git

  5. Review the docker-stack.yml:

    • How many services are being started?
    • What services are there?
  6. From the example-voting-app directory, deploy the stack: docker stack deploy --compose-file docker-stack.yml vote

    The stack will start ingress listeners on 5001 (voting app), 5002 (results app), and 8080 (Visualizer).

  7. On the top of the PWD page, click the 8080 link to engage the visualizer.

    • How many nodes do we have running?
    • How what containers are running?
    • Do some services have multiple instances?
  8. Click the 5000 and 5001 links to open the application.

  9. Register a vote and see the results get updated. Remove the cookies for the site to register multiple votes.

Cats vs Dog Part 2

Objective: To deploy applications updates to the swarm.

The development team has updated our application images and push them two Docker Hub, and we need to deploy it. The tags before is not longer to be used; the update is saved with the tag after.

We can deploy the change two ways. We can either do it with the stack file or manually through the docker service update. Partner with someone, pick one type and watch your partner use the other method.

Stackfile Method

  1. Update the docker-stack.yml file changing any references of before to after.

  2. Deploy the change: docker stack deploy --compose-file docker-stack.yml vote

  3. Checkout the analyzer. What changes do you notice?

Manual Update Method

  1. Update each service:

    • docker service update --image dockersamples/examplevotingapp_vote:after vote_vote
    • docker service update --image dockersamples/examplevotingapp_result:after vote_result

    Note that we have to specify the stack namespace because we initially deployed the stack with a compose/stack file.

  2. Checkout the analyzer. What changes do you notice?

Massive Growth!

Objective: See how to add nodes and scale the application.

Great news!!! Our site is hugely popular. We need to increase capacity of our public facing application.

We could update via the stack file or the manual method. Let's use the manual method:

  1. Add two more nodes to our cluster, but adding instances and running the command from step #3 on the new nodes.

  2. Check the visualizer.

  3. Let's increase the replicas of vote_vote: docker service scale vote_vote=4

  4. Check the visualizer.

The Boom is Over

Objective: To reduce the scale of our application and size of our swarm.

The boom is over... let's reduce our number of instances to 3.

  1. Update the docker-stack.yml.

  2. Find the vote service and change replicas to 3.

  3. Deploy the stack change: docker stack deploy --compose-file docker-stack.yml vote

  4. Put node4 in a pause state: docker node update --availability pause node4

  5. From the node4 console, leave the swarm: docker swarm leave

  6. On a manager node, list the nodes: docker node ls

  7. Remove a node: docker node rm node4

  8. Terminate the node.

Extra credit ramp up a few more nodes.

Extra Credit Activities

Try these activities at your own risk. These activities may not have been tested out recently.

Try out Portainer

To launch portainer on a non-Swarm Docker instance, run:

docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer

To launch portainer on a Swarm, run the following on a Manager node:

curl -L https://downloads.portainer.io/portainer-agent-stack.yml -o portainer-agent-stack.yml
docker stack deploy --compose-file=portainer-agent-stack.yml portainer

Access Portainer at http://localhost:9000 (if running in PWD, use the links at the top of the page).

Try out Mesos

To create a local Mesos cluster, run:

docker run --rm --privileged -p 5050:5050 -p 5051:5051 -p 8080:8080 mesos/mesos-mini

It will launch one Mesos master, one Mesos agent, and one example framework (Marathon) in the Docker container.

For additional information on launching a container with Mesos, hit up https://mesos.apache.org/blog/mesos-mini/

Cleanup

Kill the stack: docker stack rm vote

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment