A Docker & Containers tutorial
Installing Docker
Ubuntu
From official docs: https://docs.docker.com/engine/install/ubuntu/
Uninstalling old versions:
sudo apt-get remove docker docker-engine docker.io containerd runc
Set up the respository
sudo apt update
Install packages to allow apt to use a repository over HTTPS:
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
Add Docker’s official GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Add Docker repository:
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
Install Docker CE
$ sudo apt update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
Verify that Docker CE is installed correctly by running the hello-world
image:
$ sudo docker run hello-world
$ sudo docker images
Manage Docker as a non-root user
The docker
daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root
and other users can only access it using sudo
. The docker
daemon always runs as the root
user.
If you don’t want to use sudo
when you use the docker
command, create a Unix group called docker
and add users to it. When the docker
daemon starts, it makes the ownership of the Unix socket read/writable by the docker
group.
To create the docker
group and add your user:
- Create the
docker
group and add your user to thedocker
group:
sudo groupadd docker
sudo usermod -aG docker $USER
2. Log out and log back in so that your group membership is re-evaluated.
Deploying Your First Docker Container
Running A Container
You can find existing images at https://store.docker.com/ or by using the command docker search <name>.
For example, to find an image for Redis, you would use:
docker search redis
The Docker CLI has a command called run which will start a container based on a Docker Image. The structure is docker run <options> <image-name>/.
To run the latest (default) release of Redis image as a background service:
docker run -d redis
If a particular version was required, it could be specified as a tag, for example, version 3.2 would be docker run -d redis:3.2.
Note: without option -d
, the container will start then stop immediately after finishing specific command. For example: docker run alpine ls /
Finding Running Containers
Lists all running containers, the image used to start the container and uptime:
docker ps
Sample out:
Get more details about a running container:
docker inspect <friendly-name|container-id>
Display messages the container has written to standard error or standard out:
docker logs <friendly-name|container-id>
Accessing Redis
The reason is that each container is sandboxed. If a service needs to be accessible by a process not running in a container, then the port needs to be exposed via the Host. Ports are bound when containers are started using -p <host-port>:<container-port> option:
docker run -d --name redisHostPort -p 6379:6379 redis:latest
By default, the port on the host is mapped to 0.0.0.0, which means all IP addresses. You can specify a particular IP address when you define the port mapping, for example, -p 127.0.0.1:6379:6379
The option -p 6379 exposes Redis but on a randomly available port. This will allow us to run multiple instances of Redis container at the same time:
docker run -d --name redisDynamic -p 6379 redis:latest
To discover that random port, use this command: docker port redisDynamic 6379
or use familiar docker ps
command.
Persisting Data
Containers are designed to be stateless, in the way that that the data stored keeps being removed when you delete and re-create a container. Binding directories (also known as volumes) with option -v <host-dir>:<container-dir> allow data to be persisted on the host. This allows you to upgrade or change containers without losing your data.
docker run -d --name redisMapped \
-v /opt/docker/data/redis:/data redisdocker ps -a
Getting access to a bash shell inside of a container
To exec a command inside the container:
docker exec {container-id} {command}
To interact with the container (for example, to access a bash shell) you could include the options -it:
docker exec -it {container-id} sh
or:
docker exec -it {container-id} /bin/bash
Get help form CLI
docker --help
docker {command} --help
Useful commands
List containers:
docker ps -a
Stop using container id
docker stop <id>
Remove a container
docker rm <id>
List images
docker images
Remove an image
docker image rm <image_name:tag or id>
Building your own Container Images
Create Dockerfile
Docker Images start from a base image. The base image should include the platform dependencies required by your application, for example, having the JVM or CLR installed.
This base image is defined as an instruction in the Dockerfile
. Docker Images are built based on the contents of a Dockerfile
. The Dockerfile
is a list of instructions describing how to deploy your application.
In this example, our base image is the Alpine version of Nginx. This provides the configured web server on the Linux Alpine distribution.
Create your Dockerfile
for building your image by copying the contents below into the editor:
FROM nginx:alpine
COPY . /usr/share/nginx/html
You should have an index.html
file as well:
<h1>Hello World</h1>
Build Docker Image
The Dockerfile is used by the Docker CLI build command. The build command executes each instruction within the Dockerfile. The result is a built Docker Image that can be launched and run your configured app.
The format is docker build -t <build-directory>. The -t parameter allows you to specify a friendly name for the image and a tag, commonly used as a version number.
docker build -t webserver-image:v1 .
Then you can view a list of all the images on the host using:
docker images
Launch the image
Launch our newly built image providing the friendly name and tag. As it’s a web server, bind port 80 to our host using the -p parameter.
docker run -d -p 80:80 --name webapp webserver-image:v1
Once started, you’ll be able to access the results of port 80 via curl docker
Container Orchestration using Docker Compose
When working with multiple containers, it can be difficult to manage the starting along with the configuration of variables and links. To solve this problem, Docker has a tool called Docker Compose to manage the orchestration, of launching, of containers.
Installing Docker Compose
Official docs: https://docs.docker.com/compose/install/
To install Docker Compose, just download latest version (found on the link above) and apply executable permission to the binary:
sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composesudo chmod +x /usr/local/bin/docker-composedocker-compose --version
Official tutorial
Another tutorial:
Docker compose file
Docker Compose files work by applying mutiple commands that are declared within a single docker-compose.yml
configuration file. The basic structure of a Docker Compose YAML file looks like this:
version: 'X'services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
redis:
image: redis
Example:
version: '3'
services:
web:
# Path to Dockerfile.
# '.' represents the current directory in which
# docker-compose.yml is present.
build: . # Mapping of container port to host
ports:
- "5000:5000"
# Mount volume
volumes:
- "/usercode/:/code" # Link database container to app container for reachability.
links:
- "database:backenddb"
database: # image to fetch from docker hub
image: mysql/mysql-server:5.7 # Environment variables for startup script
# container will use these variables
# to start the container with these define variables.
environment:
- "MYSQL_ROOT_PASSWORD=root"
- "MYSQL_USER=testuser"
- "MYSQL_PASSWORD=admin123"
- "MYSQL_DATABASE=backend"
# Mount init.sql file to automatically run
# and create tables for us.
# everything in docker-entrypoint-initdb.d folder
# is executed as soon as container is up nd running.
volumes:
- "/usercode/db/init.sql:/docker-entrypoint-initdb.d/init.sql"
Useful commands
These commands should be run inside a folder with docker-compose.yml
.
Builds images in the docker-compose.yml
file:
docker-compose build
Create and start containers:
docker-compose up
Start and run containers in background (detach mode):
docker-compose up -d
Stops the running containers of specified services:
docker-compose stop
List all the containers in the current docker-compose file:
docker-compose ps
Remove containers, networks and images (for services defined in the compose file):
docker-compose down
Scale with multiple instances of a service:
docker-compose up -d --scale SERVICE=NUM
for example:
docker-compose up -d --scale workers=5