Objective: This is a basic container used to ensure that Docker is installed and working.
-
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.
Objective: To familiarize ones self with Docker Hub, searching for images, etc.
-
Go to https://hub.docker.com.
-
Search for an application you are interested in. Some suggestions might include
httpd
,mariadb
,mysql
, orredmine
. -
Does the image appear to come from a reputable source? Is it an automated build? Is there a link to the GitHub source?
-
Examine the readme. Is there enough documentation for you to run the aplication?
-
What tags are available for the image?
Objective: To become with familiar with the docker container
subset of commands.
-
Show a list of running containers:
docker container ps
-
Show a list of all containers:
docker container ps -a
-
Start a dettached container from one you identified in the last exercise:
docker container run -d <imageName>
-
List the running containers:
docker container ps
-
Connect to (terminal into) the container container:
docker container exec -it <containerIdOrName> bash
-
List the processes running within the container:
ps aux
-
Feel free to look around the container's file system:
ls
-
Exit the container:
exit
-
Did the container produce any logs?:
docker container logs <containerIdOrName>
-
Stop the container:
docker container stop <containerIdOrName>
-
Delete the container:
docker container rm <containerIdOrName>
Objective: To build and run an image using Dockerfile.
-
Create a directory for your project.
-
In the directory create a file called
Dockerfile
with the following contents:FROM httpd COPY website/ /usr/local/apache2/htdocs/
-
Create a sub directory named
website
. -
Create an HTML file in the
website
directory calledindex.html
. -
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>
-
Build the image giving it a name of
class
:docker image build --tag=class:v1 .
-
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. -
Can you access your page at
http://localhost/
? -
Stop your container:
docker container stop myweb
-
Refresh your website's page in the browser. Does it work?
You should not be able to as the container/process is stop.
-
Remove the container:
docker container rm myweb
Objective: To see how image tagging works.
-
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>
-
Build the image changing the image's tag:
docker image build --tag=class:v2 .
-
Try running your image (giving it a name
myweb
):docker container run -d -p 80:80 --name myweb class:v2
-
Can you access your updated page at
http://localhost/
? -
Stop and remove the container.
Objective to use the docker image
subset of commands.
-
Review the list of images on your host:
docker image ls
If the list is too long try;
docker image ls class
-
What layers are apart of your image:
docker image history class:v2
-
Remove the first version of our class image:
docker image rm class:v1
Objective: Using our website created in the last set of exercises, understand the basics of working with Docker Volumes.
-
Create a volume:
docker volume create website
-
Modify our website's Dockerfile by adding a command some where after the FROM line:
VOLUME /usr/local/apache2/htdocs/
-
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).
-
Start the image:
docker container run -d -p 80:80 --name myweb --mount source=website,target=/usr/local/apache2/htdocs/ class:v3
-
When browsing your page, it should be the same as before.
-
Stop and remove the container.
-
Now, change the webpage in some noticable way.
-
Rebuild and redeploy your application using the new image. Which page is being used?
-
Stop and remove the container.
-
Delete the volume (
docker volume rm website
) and recreate it. -
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.
Objective: To understand the basics of working with bind mounts.
-
Create a new HTML file called
index.html
, but not in ourwebsite/
directory. -
(Stop and remove any previously running containers.)
-
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. -
Browse to http://localhost/test/.
-
Stop the container:
docker container stop myweb
-
Change the new HTML file.
-
Start the container:
docker container start myweb
-
Refresh the webpage.
Objective: To understand the basics of working with Docker Networks by running a WordPress container connected to a MySQL DB container.
-
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. -
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
-
Browse to http://localhost
Did this work? Probably not. Why not?
-
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. -
List out the existing (software defined networks) in Docker:
docker network ls
-
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. -
What subnet will the containers be on?
docker network inspect wordpress-nw
-
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
-
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
-
Browse to http://localhost
-
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 therm
operation.
Objective: To see how the Docker Compose tool works.
- 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
-
Start the containers
docker-compose up
-
Trying browsing to http://localhost.
-
Ctrl+C will stop the containers. Use
docker-compose up -d
to run the containers in a detached manner. -
Clean-up things up with :
docker-compose down -v
-v
removes any volumes associated with the compose file/containers.
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.
Objective: To create a swarm and deploy an application stack to the swarm.
-
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.
-
Create a second host instance by copying the command outputted from the
swarm init
command, and run it in the second instance. -
On the first instance, run
docker node ls
-
Clone the voting app project:
git clone https://github.com/dockersamples/example-voting-app.git
-
Review the
docker-stack.yml
:- How many services are being started?
- What services are there?
-
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), and8080
(Visualizer). -
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?
-
Click the
5000
and5001
links to open the application. -
Register a vote and see the results get updated. Remove the cookies for the site to register multiple votes.
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.
-
Update the
docker-stack.yml
file changing any references ofbefore
toafter
. -
Deploy the change:
docker stack deploy --compose-file docker-stack.yml vote
-
Checkout the analyzer. What changes do you notice?
-
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.
-
Checkout the analyzer. What changes do you notice?
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:
-
Add two more nodes to our cluster, but adding instances and running the command from step #3 on the new nodes.
-
Check the visualizer.
-
Let's increase the replicas of
vote_vote
:docker service scale vote_vote=4
-
Check the visualizer.
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.
-
Update the
docker-stack.yml
. -
Find the
vote
service and changereplicas
to3
. -
Deploy the stack change:
docker stack deploy --compose-file docker-stack.yml vote
-
Put
node4
in a pause state:docker node update --availability pause node4
-
From the
node4
console, leave the swarm:docker swarm leave
-
On a manager node, list the nodes:
docker node ls
-
Remove a node:
docker node rm node4
-
Terminate the node.
Extra credit ramp up a few more nodes.
Try these activities at your own risk. These activities may not have been tested out recently.
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).
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.
- Access Mesos master UI at http://localhost:5050 (if running in PWD, use the links at the top of the page).
- Access Mesos agent at http://localhost:5051 (if running in PWD, use the links at the top of the page).
- Access Marathon UI at http://localhost:8080 (if running in PWD, use the links at the top of the page).
For additional information on launching a container with Mesos, hit up https://mesos.apache.org/blog/mesos-mini/
Kill the stack: docker stack rm vote