Table of Contents

Технология Docker

Методические идеи

Установка

Ubuntu

# apt install docker.io

Debian

Debian 10

# apt install ca-certificates curl gnupg lsb-release

# curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list

# apt update

# apt install docker-ce docker-ce-cli containerd.io

Тестирование установки

# systemctl status docker

# docker info

# docker run hello-world

Предоставление прав непривилегированным пользователям

# usermod -aG docker gitlab-runner

# su - gitlab-runner

Работа с образами и контейнерами

Обзор и удаление

# docker images

# docker ps -a
# docker container ls -a

# docker start -i NNNNNNNNNNN

# docker rm $(docker ps -aq)

# docker rm $(docker ps -q -f status=exited)

# docker rmi hello-world

# docker rmi -f $(docker images -aq)

# docker system prune

# docker system prune -a --volumes

Копирование файлов в контейнер

root@webinar:~# docker cp ca.crt greenlight-v3:/usr/local/share/ca-certificates/

root@webinar:~# docker exec -ti greenlight-v3 /usr/sbin/update-ca-certificates

root@webinar:~# docker exec greenlight-v3 wget -O /dev/null https://keycloak.corp13.un

root@webinar:~# docker commit greenlight-v3 bigbluebutton/greenlight:v3

Создание контейнера для приложения вручную

server# docker run -it --name webd --hostname webd debian bash

webd# apt update && apt install file procps nano
webd/# cat start.sh
#!/bin/sh

/etc/init.d/inetutils-inetd start

bash
server# docker ps -a

server# docker diff webd
server# docker start webd

server# docker attach webd

root@webd:/# chmod +x start.sh
server# docker commit webd test/webd

gitlab-runner@server:~$ docker images

Создание контейнера для приложения с использованием Dockerfile

server# mkdir /root/webd/ && cd /root/webd/
  или
gitlab-runner@server:~$ mkdir -p ~/webd/webd/ && cd ~/webd/webd/

server# cp /usr/local/sbin/webd .

или
gitlab-runner@server:~/webd/webd$ nano webd      # добавляем закомментированные строки

server# ###tar -cvzf www.tgz -C /var/ www/

server# cat start.sh
#!/bin/sh

/etc/init.d/inetutils-inetd start

touch /var/log/webd.log
#chown 10003 /var/www/
  
if [ "$MYMODE" = 'TEST' ]; then
  bash      # not work in k8s
else
  tail -f /var/log/webd.log
fi
server# cat Dockerfile
#FROM debian:buster
FROM debian:bullseye

RUN cp /usr/share/zoneinfo/Etc/GMT-3 /etc/localtime \
    && apt-get update \
    && apt-get install -y inetutils-inetd file \
    && apt-get clean \
    && echo 'www stream tcp nowait root /usr/local/sbin/webd webd' > /etc/inetd.conf

COPY start.sh /
COPY webd /usr/local/sbin/webd
### ADD www.tgz /var/

### for helm readiness/liveness Probe 
### COPY index.html /var/www/

EXPOSE 80
#ENV MYMODE=TEST

ENTRYPOINT ["/start.sh"]
# docker build -t test/webd .

# docker history test/webd

Dockerfile Multistage Building

student@client1:~/gowebd$ cat Dockerfile
FROM golang
#FROM golang as builder

WORKDIR /build
COPY . .
RUN test -e go.mod || go mod init gowebd

#ENV CGO_ENABLED=0
RUN go build -o /gowebd

#FROM alpine
#COPY --from=builder /gowebd /gowebd

ENTRYPOINT ["/gowebd"]
student@client1:~/gowebd$ docker images

student@client1:~/gowebd$ time docker build -t gowebd .
real    6m2.564s

student@client1:~/gowebd$ docker run -d -p 8080:80 --rm gowebd

Запуск в режиме демона и подключение к контейнеру

1-й пример - запуск образа сделанного “вручную”, можно запустить несколько экземпляров с -p 80 выяснить назначенные порты, настроить keepalived и провести нагрузочное тестирование

server# docker run --name webd01 --hostname webd01 -itd -v /var/www/:/var/www/ -p 8000:80 test/webd /start.sh

2-й пример - через Dockerfile задан entrypoint и expose, ключ –rm для удаления контейнера после остановки, добавить, при необходимости, -v

server# docker run --name webd01 -e MYMODE=TEST -itd --rm -P test/webd

3-й раз - запустить несколько экземпляров, указав параметры для подключения внешнего каталога /var/www/, выяснить назначенные порты, настроить keepalived, по журналам определять какой контейнер используется

Процессы контейнера и системы

server# docker top webd01

server# ps axw | grep inetd
server# ps axw | grep start.sh

server# cat /proc/<PID>/cgroup

server# systemd-cgls

server# cat /sys/fs/cgroup/memory/docker/NNNNNNNNNNNNNNNNNNNNNNNNNNNNN/memory.max_usage_in_bytes

server# docker stats

server# lsns | grep start.sh

Анализ параметров запущенного контейнера

server# docker inspect webd01

server# docker inspect webd01 -f {{.NetworkSettings.IPAddress}}

server# wget -qO - http://172.17.0.2/
server$ curl --noproxy '*' http://172.17.0.2/

server# docker port webd01

server# docker logs webd01

node1# docker logs webd01 -f

server# wget -qO - http://localhost:8000/
server$ curl http://localhost:8000
server$ curl http://localhost:8000/not_exit_file

host browser -> http://server.corpX.un:8000/

server# docker attach webd01 

server# docker exec -it webd01 bash

webd01# ps ax
  или
webd01# ls /proc/
webd01# cat /proc/1/cmdline

webd01# ss -tpan
  или
webd01# cat /proc/net/tcp
webd01# cat /proc/net/tcp6

Ctrl+P, Q(still holding Ctrl)

server# docker stop webd01

server# docker inspect webd01

server# docker start webd01

host browser -> http://server.corpX.un:8000/

server# docker stop webd01 && docker rm webd01

Микросервисы

# docker search sftp

# chown -R 10003 /var/www

# docker run --name sftp01 -v /var/www:/home/user3/www -p 2222:22 -d atmoz/sftp user3:password3:10003

# docker exec -it sftp01 bash

Ctrl+D

# docker top sftp01

# sftp -P 2222 user3@localhost
# docker logs sftp01

# docker stop sftp01

docker-compose

# apt install docker-compose

debian11# service docker start

# cat docker-compose.yml
version: "3"
services:
  webd:
    image: test/webd
    build: webd/
    ports:
      - "8000:80"
#      - "80"
    volumes:
      - /var/www/:/var/www/
#      - vol1:/var/www/

#    environment:
#      - MYMODE=TEST
#    stdin_open: true
    tty: true
    
  sftp:
    image: atmoz/sftp
    ports:
      - "2222:22"
    volumes:
      - /var/www/:/home/user3/www
#      - vol1:/home/user3/www
    command: user3:password3:10003
#volumes:
#  vol1:
# docker-compose build

# docker-compose up -d

# docker-compose stop

# docker-compose start

# docker-compose down

# docker-compose rm

# docker volume rm root_vol1

gitlab-runner@server:~/webd$ docker-compose up -d --scale webd=N

gitlab-runner@server:~/webd$ docker ps

gitlab-runner@server:~/webd$ docker-compose down
gitlab-runner@server:~/webd$ cat docker-compose.yml
version: "3"
services:
  webd:
    image: server.corpX.un:5000/student/webd:ver1.N
    ports:
      - "80"
    volumes:
      - /var/www/:/var/www/
    deploy:
      mode: replicated
      replicas: 3
node1,2,3# docker-compose --compatibility up -d

node1,2,3# docker-compose --compatibility down

node1,2,3# docker ps -q | xargs -l docker port | sort -n

Локальные репозитории

Insecure Private Registry

# cat /etc/docker/daemon.json
{
  "insecure-registries" : ["server.corpX.un:5000"]
}
# service docker restart

gitlab-runner@server:~$ docker login http://server.corpX.un:5000

gitlab-runner@server:~$ less ~/.docker/config.json
{
        "auths": {
                "server.corpX.un:5000": {
                        "auth": "c3R1ZGVudDpQYSQkdzByZA=="
                }
        }
}
gitlab-runner@server:~$ docker images

gitlab-runner@server:~$ docker tag test/webd server.corpX.un:5000/student/webd
gitlab-runner@server:~$ docker tag test/webd server.corpX.un:5000/student/webd:1.1

gitlab-runner@server:~$ docker images

gitlab-runner@server:~$ docker push server.corpX.un:5000/student/webd
gitlab-runner@server:~$ docker push server.corpX.un:5000/student/webd:1.1
...
node1_2_3# docker run --name webd01 --hostname webd01 -itd --rm -p 8000:80 server.corpX.un:5000/student/webd

node1_2_3# docker run --name webd0N --hostname webd0N -itd --rm -P -v /var/www/:/var/www/ server.corpX.un:5000/student/webd

Secure Private Registry

# docker pull server.corp13.un:5050/student/gowebd

# docker login server.corp13.un:5050

Использование образа Docker Registry и on-premise CA

gate# docker run -d -p 5000:5000 -v /root:/certs -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/gate.crt -e REGISTRY_HTTP_TLS_KEY=/certs/gate.key --name registry registry:2

node1# cp ~vagrant/gate.crt /etc/docker/certs.d/gate.corp13.un\:5000/ca.crt

node1# service docker restart

node1# docker tag val/webd:latest gate.corp13.un:5000/webd

node1# docker push gate.corp13.un:5000/webd

node1# curl --insecure -X GET https://gate.corp13.un:5000/v2/_catalog
{"repositories":["webd"]}

val@gitlab-vkube:~$ curl -s https://gitlab-vkube.bmstu.ru:5000/v2/postgresql/tags/list | jq
{
  "name": "postgresql",
  "tags": [
    "13"
  ]
}

Дополнительная информация

Приложение apwebd

~/apwebd$ cat Dockerfile
FROM debian:bookworm

RUN cp /usr/share/zoneinfo/Etc/GMT-3 /etc/localtime \
    && apt-get update \
    && apt-get install -y findutils gettext-base apache2 libapache2-mod-auth-openidc \
    && apt-get clean \
    && a2enmod cgid \
    && a2enmod auth_openidc

COPY rootfs/ /

EXPOSE 80

ENTRYPOINT ["/start.sh"]
~/apwebd$ find rootfs/ -type f | xargs tail -n +1
==> rootfs/var/www/html/index.html.apwebd-template <==
<HTML>
  <HEAD>
    <META HTTP-EQUIV="Refresh" CONTENT="10;URL=/cgi-bin/apwebd/">
  </HEAD>
  <BODY text="blue">
    <H1><A HREF=/cgi-bin/apwebd/>Login to ${APWEBD_HOSTNAME}</A></H1>
    Version: 1.2
  </BODY>
</HTML>
==> rootfs/start.sh <==
#!/bin/sh

[ "$APWEBD_HOSTNAME" ] || { echo Please set env APWEBD_HOSTNAME; exit; }
[ "$KEYCLOAK_HOSTNAME" ] || { echo Please set env KEYCLOAK_HOSTNAME; exit; }
[ "$REALM_NAME" ] || { echo Please set env REALM_HOSTNAME; exit; }

find / -type f -name '*.apwebd-template' | while read -r FILE; do envsubst < "$FILE" > "${FILE%.apwebd-template}"; done

/etc/init.d/apache2 start

tail -f /var/log/apache2/error.log -f /var/log/apache2/access.log
==> rootfs/etc/apache2/conf-available/serve-cgi-bin.conf.apwebd-template <==
<IfModule mod_alias.c>
        <IfModule mod_cgi.c>
                Define ENABLE_USR_LIB_CGI_BIN
        </IfModule>

        <IfModule mod_cgid.c>
                Define ENABLE_USR_LIB_CGI_BIN
        </IfModule>

        <IfDefine ENABLE_USR_LIB_CGI_BIN>

                OIDCSSLValidateServer Off
                OIDCProviderMetadataURL https://${KEYCLOAK_HOSTNAME}/realms/${REALM_NAME}/.well-known/openid-configuration
                OIDCRedirectURI http://${APWEBD_HOSTNAME}/cgi-bin/apwebd
                OIDCClientID any-client
                OIDCCryptoPassphrase anystring

                ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
                <Directory "/usr/lib/cgi-bin">
                        AllowOverride None
                        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
#                       Require all granted
                        AuthType openid-connect
                        Require valid-user
                </Directory>
        </IfDefine>
</IfModule>
==> rootfs/usr/lib/cgi-bin/apwebd <==
#!/bin/sh

echo Content-type: text/html
echo

echo "<h1 style=\"color:blue;\">Hello ${OIDC_CLAIM_preferred_username}</h1>"

echo "<pre>"; env; echo "</pre>"
~/apwebd$ docker build -t server.corp13.un:5000/student/apwebd:ver1.2 .

~/apwebd$ docker run -e APWEBD_HOSTNAME=apwebd.corp13.un -e KEYCLOAK_HOSTNAME=keycloak.corp13.un -e REALM_NAME=corp13 -itd --rm -P server.corp13.un:5000/student/apwebd:ver1.2

~/apwebd$ docker run -e APWEBD_HOSTNAME=apwebd.corp13.un -e KEYCLOAK_HOSTNAME=keycloak.corp13.un -e REALM_NAME=corp13 -itd --entrypoint bash server.corp13.un:5000/student/apwebd:ver1.2

~/apwebd$ docker push server.corp13.un:5000/student/apwebd:ver1.2

Старая версия

Работа с образами

# docker search debian

# docker pull debian

# docker images

# docker commit debian_cont_01 debian_img_01

# docker rmi debian_img_01

Работа с контейнерами

# docker create -i -t --name debian_cont_01 debian

# docker ps -a
# docker container ls -a

# docker update --restart=always debian_cont_01
# docker start debian_cont_01

# docker ps
# docker container ls

# docker inspect debian_cont_01

# docker top debian_cont_01

# docker attach debian_cont_01

:/# apt update

:/# apt install iputils-ping

:/# ping -c1 ya.ru
Ctrl+P, Q(still holding Ctrl)

# docker stop debian_cont_01

# docker rm debian_cont_01

# docker rm $(docker ps -aq)

Работа с сетью

Управление сетями

# docker network ls

# docker network create --subnet=192.168.200+X.0/24 corpX_dmz

# docker run -h mail.corpX.un --net corpX_dmz --ip 192.168.200+X.10 -i -t --name debian_cont_01 debian

# docker network inspect corpX_dmz

Назначение публичного ip для контейнера

Вариант 1

Использование bridge

Вариант 2

Использование nat/dnat

# ip addr add 172.16.1.100+X dev eth2

# iptables -t nat -A POSTROUTING -o eth2 -s 192.168.100+X.10 -j SNAT --to-source 172.16.1.100+X
# iptables -t nat -A PREROUTING -i eth2 --destination 172.16.1.100+X -j DNAT --to-destination 192.168.100+X.10

HEARTBEAT и Docker

nodeN# cat haresources
node1.corpX.un drbddisk Filesystem::/dev/drbd0::/disk2::ext4 docker