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+c
to 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/sshd
for building and managing this container.mkdir -p /var/docker/sshd
cd /var/docker/sshd/ -
We can use a
Dockerfile
in 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:12
and 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.sh
that generates an ssh key pair and makes sure that the public key is saved to~/.ssh/authorized_keys
inside 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
/tmp
dir 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=/host
that we used on the commanddocker create
makes sure that the current directory is mounted to the director/host
inside the container.Besides, the instruction
WORKDIR /host
in theDockerfile
sets the default working directory for the commands that are run bydocker exec
.These explain why the keys are generated on the directory
/host
inside 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
/host
inside the container, and because/host
is 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
sshkey
to 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.al
Note: We have to copy/transfer the
sshkey
first.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/