Docker
Installation
Steps are pulled from a Digital Ocean tutorial.
Update list of packages and install prerequisites.
sudo apt update && \ sudo apt install apt-transport-https ca-certificates curl software-properties-common
Add the GPG key for the official Docker repository.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Add the Docker repository to APT sources and update package list from the new repo.
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
Make sure install is pulling from Docker repo instead of default Ubuntu.
apt-cache policy docker-ce
Install Docker.
sudo apt install docker-ce
Check that Docker is running.
sudo systemctl status docker
Execute Docker commands without sudo.
sudo usermod -aG docker ${USER} && \ su - ${USER}
Verify user is now added to the docker group.
groups
Resources
Image vs. Container
Image - Application we want to run
Container - Instance of that image running as a process
Docker Basics
Create an Nginx container
docker run -p 80:80 -d --name webhost nginx
- Downloads Nginx from Docker Hub
- Starts new container from that image
- Opened port 80 on host IP
- Routes port 80 traffic to the container IP, port 80
- View container at http://localhost:80
Other examples
docker run -p 80:80 -d --name nginx nginx
docker run -p 8080:80 -d --name httpd httpd
docker run -p 3306:3306 --platform linux/amd64 -d --name mysql -e MYSQL_RANDOM_ROOT_PASSWORD=true mysql
Create a JupyterLab instance and attach your current directory as a volume: docker run -it --rm -p 8888:8888 -v $(PWD):/home/jovyan jupyter/pyspark-notebook
Processes and configurations
Check processes running inside a container: docker top <container>
Container configuration: docker <container> inspect
Check container stats (memory, cpu, network): docker stats <container>
Getting a shell inside containers
Start a new container interactively: docker run -it <container>
Run commands in existing container: docker exec -it <container>
Example: Start a container interactively and launch bash within it
- Start container and launch bash:
docker run -it --name ubuntu ubuntu bash
- Run some bash command:
apt-get install -y curl
- Exit the container:
exit
- Start and re-enter the container:
docker start -ai ubuntu
Example: Launch shell in running container
docker exec -it <container> bash
Pull an image from docker hub
docker pull <imagename>
Docker Networks
- Each container is connected to a private virtual network (called “bridge”).
- Each virtual network routes through NAT firewall on host IP.
- All containers on a virtual network can talk to each other without
-p
- Best practice: Create a new virtual network for each app.
- You can skip virtual networks and use the host IP (
--net=host
).
Get container IP: docker inspect --format '{{ .NetworkSettings.IPAddress }}' <container>
Publishing (#:#)
example: 8080:80
left number: published/host port
right number: listening/container port
Traffic passing through port 8080 on the HOST will be directed to port 80 on the container.
DNS
Docker uses container names as host names.
Dont rely on IPs for inter-communication.
Best Practice Always use custom networks.
Assignment
Check different curl versions within current versions of Ubuntu and CentOS.
Run “curl –version” on both operating systems.
Steps
ubuntu: apt-get update && apt-get install curl
centos: yum update curl
Then…
curl --version
Also:
Check out command docker --rm
Dockerfiles
Recipe for creating images
Each Dockerfile stanza such as “RUN”, “CMD”, etc. are stored as a single image layer. Docker caches each layer by giving it a unique SHA (hash), so whenever the image is (re)built, it can check to see if a layer has changed, and if not, it will use the cached layer.
Docker builds images top down, so it is best practice to structure the Dockerfile in such a way that lines which will change the most are at the bottom, and lines that will change the least are at the top. If a line is changed (ie. source code changes) Docker will rebuild that line, and thus each line after that will also need to be rebuilt.
Keeping the Docker system clean
docker system prune
- all stopped containers - all networks not used by at least one container - all dangling images - all dangling build cache
Volumes an Bind Mounts
Volumes - Special location outside of container UFS
Bind Mounts - Link container path to host path
Build an image and named volume (persistent): docker run -d --name mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=True -v mysql:/var/lib/mysql --platform linux/amd64 mysql
Rebuilding a Compose Service
docker compose up -d --no-deps --build <service_name>