Docker Intro
1. Install
- 
Get Docker’s official GPG key: wget https://download.docker.com/linux/ubuntu/gpg \
 -O /etc/apt/keyrings/docker.asc
 ls -l /etc/apt/keyrings/docker.asc
- 
Add the docker sources to the apt list: cat <<EOF > /etc/apt/sources.list.d/docker.sources
 Types: deb
 URIs: https://download.docker.com/linux/debian
 Suites: bookworm
 Components: stable
 Signed-By: /etc/apt/keyrings/docker.asc
 EOF
 cat /etc/apt/sources.list.d/docker.sources
- 
Install: apt update
 apt install --yes \
 docker-ce \
 docker-ce-cli \
 containerd.io \
 docker-buildx-plugin \
 docker-compose-plugin
- 
Check: docker --version
 docker compose version
 systemctl status docker
 docker run hello-world
2. Testing
- 
Run a command: docker run \
 --name test1 \
 debian:12 \
 echo 'Hello World!'
 docker image ls
 docker ps
 docker ps -a
- 
Run a loop: docker run \
 --name test2 \
 debian:12 \
 /bin/sh -c "while true; do date; sleep 1; done"
 docket ps
 docker ps -aNote: Press Ctrl+cto stop it.
- 
Starting, stopping, checking the logs: docker start test1
 docker ps
 docker logs test1
 docker start test1
 docker ps
 docker logs test1
 docker start test2
 docker logs test2 -f
 docker ps
 docker stop test2
 docker ps
 docker ps -a
- 
Run a shell in a container: docker run --name test3 -i -t ubuntu bash
 cat /etc/os-release
 ps aux
 exit
 docker ps
 docker ps -a
 docker image ls
- 
Start a shell in a container: docker start test2
 docker ps
 docker exec -it test2 bash
 cat /etc/os-release
 ps aux
 apt update
 apt list procps
 apt install procps
 ps aux
 top
 free -h
 df -h .
 exit
- 
Some other commands: docker ps -a
 docker ps -a --format "{{.ID}}: {{.Names}}"
 docker image ls
 docker image history hello-world
 docker inspect test1 | less
 docker inspect test2 | less
 docker --help | less
 docker run --help | less
- 
Clean up: docker ps -a
 docker rm test1 test2 test3
 docker ps -a
 docker image ls
 docker rmi ubuntu debian:12 hello-world
3. Run a web server
- 
Get the image: docker search welcome-to-docker --limit=5
 docker pull docker/welcome-to-docker
 docker image ls
 docker image history docker/welcome-to-docker
- 
Start the container: docker run \
 --name nginx \
 -p 8081:80 \
 docker/welcome-to-dockerStop it with Ctrl+c. Then run it again with the option-d:docker rm nginx
 docker run -d \
 --name nginx \
 -p 8081:80 \
 docker/welcome-to-docker
 docker ps
 docker logs nginx -f
- 
Open in browser http://nginx.user1.fs.al:8081/ Refresh the page and check the logs again. Stop the logs with Ctrl+c.
- 
Look inside: docker exec -it nginx /bin/sh
 cat /etc/os-release
 ps aux
 top
 ls /etc/nginx/
 ls /etc/nginx/conf.d/
 less /etc/nginx/conf.d/default.conf
 exit
- 
Clean up: docker stop nginx
 docker rm nginx
 docker image ls
 docker rmi docker/welcome-to-docker
Did you notice that we could access the port 8081 although we didn't
open it in the firewall? If we forward a port to a container, docker
will make sure to open that port on the firewall. So, we should be
careful when we forward a port to a container, because it will be
available to the whole world.
firewall-cmd --list-all
firewall-cmd --get-active-zones
firewall-cmd --zone=docker --list-all
firewall-cmd --zone=docker --list-interfaces
There is no easy way to fix this issue. One workaround is to use the firewall of the VPS provider, in order to make sure that only the ports that we want are allowed. Docker cannot mess with that firewall.
Another way is to restrict port forwarding only to the localhost. For
example, if we use -p 127.0.0.1:8081:80 instead of -p 8081:80,
then the port 8081 can be accessed only from the localhost.
4. An openssh container
- 
Let's use the directory /var/docker/sshdfor building and managing this container.mkdir -p /var/docker/sshd
 cd /var/docker/sshd/
- 
We can use a Dockerfilein order to build the image:cat <<'_EOF_' > Dockerfile
 # syntax=docker/dockerfile:1.4
 FROM debian:12
 RUN apt update && apt upgrade --yes
 RUN apt install --yes procps
 RUN <<EOF
 # install openssh-server
 apt install --yes openssh-server
 mkdir -p /var/run/sshd
 sed -i /etc/ssh/sshd_config \
 -e 's/^#PermitRootLogin .*/PermitRootLogin prohibit-password/'
 EOF
 WORKDIR /host
 CMD ["/usr/sbin/sshd", "-D"]
 _EOF_We are starting from the base image of debian:12and are creating additional layers on it, by installing other things.
- 
Build the image: docker build -t sshd-image .
 docker image ls
- 
Create the container and start it: cat <<'_EOF_' > create.sh
 #!/bin/bash -x
 docker create \
 --name=sshd \
 --mount type=bind,source=$(pwd),destination=/host \
 --publish 2201:22 \
 --restart=unless-stopped \
 --hostname openssh \
 sshd-image
 _EOF_chmod +x create.sh
 docker ps -a
 docker start sshd
 docker ps
- 
Look inside the container: docker exec -it sshd bash
 ps aux
 top
 pwd
 ls -al
 exit
- 
Let's create the script setup-key.shthat generates an ssh key pair and makes sure that the public key is saved to~/.ssh/authorized_keysinside the container:cat <<'_EOF_' > setup-key.sh
 #!/bin/bash -x
 # generate a key pair
 [[ -f /host/sshkey ]] \
 || ssh-keygen -t ecdsa -f /host/sshkey -q -N ''
 # copy public key to authorized_keys
 mkdir -p /root/.ssh
 chmod 700 /root/.ssh
 cat /host/sshkey.pub > /root/.ssh/authorized_keys
 chmod 600 /root/.ssh/authorized_keys
 _EOF_chmod +x setup-key.sh
- 
Let's copy this script to the /tmpdir inside the container, and then execute it:docker cp setup-key.sh sshd:/tmp/
 docker exec sshd ls -l /tmp/
 docker exec sshd /tmp/setup-key.shIt will generate an ssh key pair, if it does not exist: ls -al
 docker exec sshd rm /tmp/setup-key.shinfoThe option --mount type=bind,source=$(pwd),destination=/hostthat we used on the commanddocker createmakes sure that the current directory is mounted to the director/hostinside the container.Besides, the instruction WORKDIR /hostin theDockerfilesets the default working directory for the commands that are run bydocker exec.These explain why the keys are generated on the directory /hostinside the container, and why we can access them outside the container as well (on the system that is hosting the container).
- 
Let's also create a script that modifies ~/.bashrc:cat <<'_EOF_' > setup-bashrc.sh
 #!/bin/bash -x
 cat << 'EOF' | tee -a /root/.bashrc
 # make ls colorized
 export LS_OPTIONS='--color=auto'
 export SHELL='/bin/bash'
 alias ls='ls $LS_OPTIONS'
 alias ll='ls $LS_OPTIONS -l'
 alias l='ls $LS_OPTIONS -lA'
 # set a better prompt
 PS1='\n\[\033[01;33m\]\u@\[\033[01;32m\]\h\[\033[00m\]:\[\033[01;34m\]\w\[\e[32m\]\n==> \$ \[\033[00m\]'
 EOF
 _EOF_chmod +x setup-bashrc.sh
 nano setup-bashrc.sh
- 
Because the current directory is mounted to /hostinside the container, and because/hostis the default working directory for the container, we can execute the script like this:docker exec sshd pwd
 docker exec sshd ls -al
 docker exec sshd ./setup-bashrc.shdocker exec -it sshd bash
 ls
 exit
- 
Let's try to use the private key sshkeyto ssh to the container, on the port2201:ssh -p 2201 -i sshkey root@localhost
 whoami
 pwdWe can try from outside the VPS, like this: ssh -p 2201 -i sshkey root@sshd.user1.fs.alNote: We have to copy/transfer the sshkeyfirst.This verifies again that once we forward a port to a container, docker will make the forwarded port available to the whole world, despite the firewall that is installed on the VPS. 
5. More examples
For more examples and a deeper understanding see: https://docs.docker.com/get-started/