2 days, 8 ac.hrs, 7 as.hrs.
- Роль
- Текущий уровень с Linux: 0–3
- Текущий уровень с Docker/Podman: 0–3
- Как поймете, что тренинг дал Вам ценность?
- Virtual machine for practice @ vra8:
IT Academy Training Group
, HDD 50Gb, OS AlmaLinux + local ssh client - Доступен git repo с данным руководством {{ git-repo }}
https://github.com/eugene-krivosheyev/podman
- Доступен {{ registry-host }}
- Доступ учетной записи {{ registry-account }} на {{ registry-host }}
- Установлен Podman и зависимости
sudo dnf update
sudo dnf install -y podman
sudo dnf install -y slirp4netns # for rootless containers
sudo dnf install -y bash-completion
source <(podman completion bash)
sudo podman completion -f /etc/bash_completion.d/podman bash
- Переносимость ПО: запуск на разных окружениях – dev, test, prod
- исполняемые файлы нашего ПО
- зависимости
- конфигурация
- аргументы командной строки
- порты
- побочные эффекты
- место на диске для гостевой ОС
- время запуска гостевой ОС
- overhead операций гостевой ОС
- Схема контейнеризации
- Host
- Image
- Image Registry
- Container
- Port Mapping
- Mounts
- Pod
puml
@startuml
node "image\nregistry" {
database "disk\nimage" as disk_image
}
node "host" {
rectangle "pod" {
rectangle "infra\ncontainer"
rectangle "container" {
component "application"
database "container\nlayer" as layer
}
}
database "disk" {
database "image"
file "volume"
folder "shared\nfolder" as folder
disk_image - image
}
image --layer
volume -# container
folder -# container
volume -# pod
folder -# pod
}
pod #--# host : "port\nmapping"
container #--# host : "port\nmapping"
@enduml
-
pod
-
bunch of containers
-
infra
container -
localhost
-
port mappings
-
mounts
-
daemonless
-
rootfull and rootless modes
Hands-on practice quest #00: Prerequisites sound-check and tools install 20 мин парной практики + 10 мин дебриф
- Пары участников с чередованием ролей в паре
- Форк данного руководства для собственных пометок
- Все команды запускаются из-под суперпользователя
sudo
или
su -
- Как описать сценарий использования команд?
- каоманды перевода системы в нужное состояние
- команды действия
- команды проверки успешности и корректности действия
- Hints
- при работе в терминале используйте
Tab
и↑
для автоподстановки значений - синонимы команд cli
... --help
- podman cli reference
- Сценарий "Как посмотреть версию подмана/информацию о хостовой ОС/занятое место?"
podman version # TODO: собственные пометки участников для будущего использования в проектах
podman system info
podman system df
- Сценарий "Как подключить корпоративный репозиторий?"
podman logout {{ registry-host }}
podman login {{ registry-host }}
-
Сценарий "Как найти нужный образ в registry?" Залогиниться браузером по адресу {{ registry-host }}, в поиске найти нужный образ и скопировать полное символьное имя (включая сетевой адрес хоста).
-
Сценарий "Как скачать образ из корпоративного репозитория?"
podman image pull {{ registry-host }}/{{ os-images-path }}/alpine:3.14
podman system df
- Сценарий "Как запустить контейнер?"
podman container run hello
podman container run --name demo -it {{ registry-host }}/{{ os-images-path }}/alpine:3.14
/# cat /etc/os-release
/# exit
- Сценарий "Как посмотреть запущенные контейнеры [все] и удалить контейнер?"
podman container ls [--all]
podman container rm demo
- Как назвали сценарии?
- Успешна ли сконфигурирована система для использования Podman?
- Откуда взялся образ диска?
- Сколько места занимает образ?
- Сколько места занимает контейнер?
- Какая версия образа скачивается по умолчанию?
- Какая гостевая команда запускается при запуске контейнера?
- Задача среды исполнения контейнеров: изоляция нашего ПО от хоста
- Отображение диска контейнера на диск хоста: образ
- Что должно быть на диске для запуска и работы контейнеризованного приложения?
- Состав образа диска (от
scratch
до prod-ready) - OS libraries
- OS package manager (для удобной установки зависимостей, нужен на этапе сборки образа)
- OS commands (для отладки, мониторинга и траблшутинга контейнеров на этапе эксплуатации)
- Application libraries
- Application executables
- Config files
- Data files
$ podman run --rm -it alpine:3.14 ls
bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
quay.io/podman/hello latest 577bf902f284 9 hours ago 85.1 kB
<none> <none> 4f391b4bf86f 3 days ago 85.1 kB
docker.io/library/alpine 3.14 376ba31ae3da 2 months ago 5.63 MB
docker.io/library/alpine latest a6215f271958 2 months ago 5.58 MB
id
как хеш образахост/группа/имя
как имя репозиторияхост/группа/имя:тег
как полное символьное имя
podman container run
+ side effects >podman container commit
>podman image push
# редко используемый "ручной" ЖЦpodman image build
>podman image push
# штатный автоматизированный ЖЦ
- Overlay FS
$ podman image history quay.io/podman/hello
ID CREATED CREATED BY SIZE COMMENT
577bf902f284 10 hours ago /bin/sh -c #(nop) LABEL "org.opencontainer... 0 B FROM d2f3fdcf80a2
<missing> 10 hours ago /bin/sh -c #(nop) LABEL "org.opencontainer... 0 B FROM cc07153b17e6
<missing> 10 hours ago /bin/sh -c #(nop) LABEL "org.opencontainer... 0 B FROM d45976f9036e
<missing> 10 hours ago /bin/sh -c #(nop) CMD ["/usr/local/bin/pod... 0 B FROM aeedbc3e44e3
<missing> 10 hours ago /bin/sh -c #(nop) COPY file:d246003209ea6b... 80.9 kB FROM a796bd9429dc
<missing> 10 hours ago /bin/sh -c #(nop) USER 1000 0 B FROM 190f78d5a9fb
<missing> 10 hours ago /bin/sh -c #(nop) LABEL artist="Máirín N... 0 B FROM 78ab72a99b9f
<missing> 10 hours ago /bin/sh -c #(nop) LABEL maintainer="Podman... 0 B
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock nate/dockviz images -t
├─<missing> Virtual Size: 5.6 MB
│ └─<missing> Virtual Size: 5.6 MB
│ └─<missing> Virtual Size: 5.6 MB
│ └─<missing> Virtual Size: 19.8 MB
│ └─<missing> Virtual Size: 19.8 MB
│ └─<missing> Virtual Size: 19.8 MB
│ └─<missing> Virtual Size: 116.7 MB
│ └─<missing> Virtual Size: 116.7 MB
│ ├─<missing> Virtual Size: 116.7 MB
│ │ └─<missing> Virtual Size: 116.7 MB
│ │ └─<missing> Virtual Size: 116.7 MB
│ │ └─<missing> Virtual Size: 136.7 MB
│ │ └─<missing> Virtual Size: 136.7 MB
│ │ └─3c1355b22f16 Virtual Size: 136.7 MB Tags: training-docker/ekr-stub:1.0.0
│ └─<missing> Virtual Size: 116.7 MB
│ └─<missing> Virtual Size: 116.7 MB
│ └─<missing> Virtual Size: 116.7 MB
│ └─<missing> Virtual Size: 116.7 MB
│ └─e96641ea7cdf Virtual Size: 182.6 MB Tags: training-docker/ekr-backend:1.0.0
- Как управлять образами c Crane
- пары участников
- Сценарий "Как посмотреть список образов?"
podman image ls # TODO: собственные пометки участников для будущего использования в проектах
- Сценарий "Как скачать образ из репы?"
podman image pull {{ registry-host }}/{{ os-images-path }}/alpine:3.14
podman image ls
- Сценарий "Как посмотреть историю создания образа и его описание (слои)?"
podman image history {{ registry-host }}/{{ os-images-path }}/alpine:3.14
podman image inspect {{ registry-host }}/{{ os-images-path }}/alpine:3.14 [| jq]
- Сценарий "Как посмотреть изменения в контейнере и сохранить их?"
podman container run --name demo -it {{ registry-host }}/{{ os-images-path }}/alpine:3.14 # run = pull + start
/# touch side-effect.txt
/# exit
podman container diff demo # используется нотация Git
podman container commit demo {{ registry-host }}/container-training-docker/{{ registry-account }}/demo # фиксируем изменения и получаем новый образ
podman image ls
- Сценарий "Как повесить тэг на образ?"
podman image tag {{ registry-host }}/container-training-docker/{{ registry-account }}/demo:latest {{ registry-host }}/container-training-docker/{{ registry-account }}/demo:1.0.0 # нужно указывать целиком символьное имя
podman image ls
- Сценарий "Как опубликовать образ в репу?"
podman image push {{ registry-host }}/container-training-docker/{{ registry-account }}/demo:1.0.0
- Сценарий "Как удалить контейнер / удалить образ из репы?"
podman image ls
podman container rm demo # удаляем контейнер
podman image prune # удаляем "подвисшие" образы -> образы, которые не имеют имени и тэга
podman image ls
podman image rm {{ registry-host }}/container-training-docker/{{ registry-account }}/demo:1.0.0 # untag = unlink в Linux
podman image ls
podman image rm {{ registry-host }}/container-training-docker/{{ registry-account }}/demo:latest
podman image ls
podman image prune --all # удаляем неиспользуемые(!) образы = нет запущенного контейнера и нет остановленного контейнера
- Как назвали сценарии?
- Какой тег у образа по умолчанию?
- В чем физический смысл удаления образа командой
rm
? - Всегда ли удаляется образ по команде
rm
? - Что делает prune?
- Что такое dangling image?
-
container = running process + container data (container layer)
-
Что значит "запуск" контейнера? Что именно там запускается?
-
Сколько по времени будет работать контейнер?
-
Как можно доопределить команду, запускаемую в контейнере?
-
Что нужно определить для запуска контейнера?
-
disk image
-
меппинг (форвардинг) портов
-
имя контейнера (+defaults)
-
virtual network
-
folder | volume mapping
-
guest environment variables
-
command line (image
entrypoint
override) -
command line arguments (image
cmd
override) -
Экстернализация конфигурации приложения
-
Задачи экстернализации конфигурации приложения
-
Способы:
--env
и аргументы командной строки -
Жизненный цикл контейнера
-
podman container create
+podman container start
=podman container run
[args]
-
podman container commit
-
podman container ls [--all]
-
podman container logs
-
podman container stop
&podman container kill
-
podman container rm
-
Запуск контейнера в интерактивном и фоновом режимах:
-
-i
vs-d
-
-t
-
podman pod create
&podman container run --pod [new:]
-
podman pod ps
-
podman pod ls
-
podman pod logs
-
podman pod stop
-
podman pod rm
- пары участников
- Сценарий "Как посмотреть список работающих и остановленных контейнеров?"
podman container ls --all
- Сценарий "Как запустить 'одноразовый' контейнер?"
podman container run --rm -it {{ registry-host }}/{{ os-images-path }}/alpine:3.14 # note `--rm`
/# exit
podman container ls --all
- Сценарий "Как запустить контейнер в фоновом режиме?"
podman container run --detach --name proxy --publish 8080:80 {{ registry-host }}/{{ software-images-path }}/nginx:1.19.4 # note `--detach` or `-d`
podman container ls
curl localhost:8080
- Сценарий "Как 'подключиться' к работающему контейнеру?"
podman container logs proxy
podman container attach --sig-proxy=false proxy # otherwise detach key `ctrl-c` will stop container
podman container top proxy
podman container exec -it proxy /bin/sh # run additional process `sh` within _running_ container
- Сценарий "Как посмотреть свойства контейнера?"
podman container port proxy
podman container inspect proxy [| jq]
- Сценарий "Как остановить и перезапустить работающий контейнер?"
podman container stop ... # send SIGTERM, and then SIGKILL after grace period
podman container kill ... # send SIGKILL, or specified signal
podman container start ...
podman container restart ...
- Сценарий "Как удалить работающий контейнер?"
podman container rm --force
- Сценарий "Как удалить остановленный контейнер?"
podman container rm ...
podman container prune ...
- Сценарий "Как создать под?"
podman ...
- Сценарий "Как запустить контейнер с добавлением его в под?"
podman ...
- Сценарий "Как посмотреть список подов?"
podman ...
- Сценарий "Как посмотреть список контейнеров в поде?"
podman pod ps
podman ps -a --pod
podman pod inspect ...
- Сценарий "Как посмотреть логи контейнеров в поде?"
podman logs --latest ...
- Сценарий "Как сгенерировать k8s manifest из готового пода?"
podman generate kube ...
- Сценарий "Как остановить под?"
podman ...
- Какие способы идентификации контейнера?
- Какое имя у контейнера по умолчанию?
- Где можно определить конфигурацию сети (например, меппинг портов) – для контейнера или для пода?
- Что за логи наблюдаются для контейнера и пода?
- В чем физический смысл удаления контейнера?
- В чем физический смысл удаления пода?
- Что делает
container prune
? - Что такое k8s manifest?
- На выходе бинарный файл образа
- На входе дескриптор сборки образа
Containerfile
/Dockerfile
- Что должно быть в этом дескрипторе?
- Ключевые директивы Containerfile
FROM
+--platform=
WORKDIR
создаст папку при необходимостиCOPY
andADD
from build context (+.dockerignore
)RUN
(+shell
and preferredexec
forms) andSHELL
for non-default shellEXPOSE
documentationENTRYPOINT
andCMD
(+ preferredexec
and similardefault parameters to ENTRYPOINT
,shell
forms)LABEL
podman container run [--entrypoint Dockerfile's ENTRYPOINT override] IMAGE [Dockerfile's CMD defaults override]
FROM alpine
ENTRYPOINT ["echo", "Hello"]
CMD ["World"] # 'default parameters to ENTRYPOINT' form
...
$ podman build --tag test .
...
$ podman run --rm test
Hello World
...
$ podman run --rm test Alpine
Hello Alpine
-
Системные образы для базы VS прикладные образы с приложениями
-
Кратко по оптимизации сборки:
-
Сборка
FROM scratch
, "пинцетный метод" -
Использование легковесных базовых образов
alpine 5.33MB
registry.access.redhat.com/ubi8/ubi-micro 51.6MB
debian:stable-slim 74.3MB
- Понятие build context и кеширование при сборке (+ .dockerignore)
- Изменение порядка директив в Dockerfile, чтобы максимально повторно использовать кеш builder
- Объединение директив, чтобы снизить количество слоёв образа
- Multi-stage build, чтобы не тащить в итоговый образ инфраструктуру сборки
- Объединение слоёв образа в один слой
- Склонирован git repo c приложением
application
└── backend
├── Containerfile
└── dbo-1.0-SNAPSHOT.jar
- Задана рабочая папка
cd application
- Проведена аутентификация консольного Podman CLI в Registry
podman login ...
- Сценарий "Как собрать образ на основе Containerfile?"
vi backend/Containerfile # Replace base image with one that suitable for corporate image registry
podman image build \
--tag {{ registry-host }}/container-training-docker/{{ registry-account }}/app:1.0.0 \ # set up symbolic name for image
./backend # folder where Containerfile located
podman image ls
- Сценарий "Как запустить 'одноразовый' контейнер на базе своего образа с приложением?"
podman container run \
--name backend \
--rm \ # одноразовый: удалится после остановки
--detach \ # -d
--publish 8080:8080 \ # -p [host address:]8080:8080
--env SPRING_PROFILES_ACTIVE=qa \ # -e: в контейнере действует переменная окружения
{{ registry-host }}/container-training-docker/{{ registry-account }}/app:1.0.0 \ # имя и тег
--spring.profiles.active=qa # параметры командной строки
- Сценарий "Как протестировать запущенное в контейнере приложение?"
podman container ls --all # Check for status
curl localhost:8080/dbo/actuator/health
open http://localhost:8080/dbo/swagger-ui/
- Сценарий "Как мягко остановить приложение средствами самого приложения?"
curl -X POST localhost:8080/dbo/actuator/shutdown
- Сценарий "Как опубликовать проверенный образ в репозитории?"
podman image push ...
- В каком порядке выполнялись директивы Dockerfile?
- Сколько новых layers добавила сборка к базовому образу?
- Когда и по какой причине остановился контейнер?
- Что происходит с процессом приложения, когда останавливаем контейнер?
- Сколько раз вы столкнулись с настройкой экстернализированной конфигурации приложения?
- Что происходит с изменениями в образе при остановке контейнера?
- Как зафиксировать изменения в образе?
- Как откатить изменения в образе?
- Как можно сохранять изменения на диске вне образа? (stateful containers): mounts
- tmpfs
podman container run
--tmpfs /tmp
--tmpfs /var/log
--tmpfs /dbo/log
- shared folders
podman container run --volume "$(pwd)"/folder/file:/folder/file:ro # пути у folder абсолютные, начинаются с "/"
- volumes
podman container run --volume my_volume:/folder/file:ro # имя volume не начинается с "/"
- Логи
- консольные логи: stdout/stderr
- собираются и упаковываются в выбранный формат (определяется log driver)
podman logs [--until=10s] ...
- Собран образ с приложением
- Сценарий "Как запустить stateful container c пробросом на хостовую папку?"
podman container run \
-- ... \ # TODO имя контейнера
-- ... \ # TODO одноразовый: удалится после остановки
-- ... \ # TODO фоновой режим
-- ... \ # TODO проброс порта на хост
-- ... \ # TODO профиль конфигурации Spring 'qa'
--volume $(pwd)/log:/dbo/log \ # -v: папка в конейнере /dbo/log отображена на папку на хосте /current-path/log. Windows caution for $()!
{{ registry-host }}/container-training-docker/{{ registry-account }}/app:1.0.0
cat $(pwd)/log/dbo.log
- В данных сценариях какой тип mount лучше подойдет? tmpfs, shared folder, volume?
- Зачем нужны оркестраторы?
- Понятие 'сервиса' в оркестраторах
- Структура дескриптора оркестратора Compose
- services
- mounts
- virtual networks
cd application
podman-compose up --detach
podman-compose ps
podman-compose logs
podman-compose down
Hands-on practice quest #05: Multi-component stateful application containerization with Compose 30 + 10
- Установлен Podman Compose
sudo dnf install -y pip
pip3 install https://github.com/containers/podman-compose/archive/devel.tar.gz
- Сценарий "Как запустить группу контейнеров под управлением Compose?"
cd application
podman-compose up --detach
- Сценарий "Как наблюдать контейнеры под управлением Compose?"
cd application
podman-compose ps
podman-compose port
podman-compose logs
- Сценарий "Как остановить и удалить контейнеры?"
cd application
podman-compose down
- Можно ли наблюдать контейнеры средствами podman, а не Compose?
- Минимизировать security риски
- Используйте минимальные образы: быстрее и меньше зависимостей + меньше рисков
- Запуск в rootless mode
- Подписывать образы и проверять подписи
- Сканеры уязвимостей для образов
docker scan --dependency-tree <image>
- Линтеры для Dockerfile
- COPY вместо ADD + .dockerignore
- Фиксированные теги для идентификации образов (Semantic versioning or Unique tags)
- Multi-Stage Build в том числе для того, чтобы в итоговый образ не утекли чувствительные данные
- Хранение и передача конфигурации и чувствительных данных: Secrets