Установка. Docker часто меняет подход установки, поэтому действуем по официальной инструкции и выполняем следующую команду, чтобы добавить пользователя в группу:
sudo adduser $(whoami) docker && newgrp docker && source ~/.bashrc
docker -v
Docker version 1.9.1, build a34a1d5
docker version
Client:
Version: 1.9.1
API version: 1.21
Go version: go1.4.2
Git commit: a34a1d5
Built: Fri Nov 20 13:12:04 UTC 2015
OS/Arch: linux/amd64Server:
Version: 1.9.1
API version: 1.21
Go version: go1.4.2
Git commit: a34a1d5
Built: Fri Nov 20 13:12:04 UTC 2015
OS/Arch: linux/amd64
docker info
Containers: 3
Images: 87
Server Version: 1.9.1
Storage Driver: aufs
Root Dir: /mnt/dsk1/docker/aufs
Backing Filesystem: extfs
Dirs: 93
Dirperm1 Supported: true
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 3.19.0-42-generic
Operating System: Ubuntu 14.04.3 LTS
CPUs: 8
Total Memory: 23.54 GiB
Name: workstation
ID: O6JG:4MOF:M526:3PJV:FQHZ:3ERJ:P7KW:U3VN:D6AZ:C46E:SSH3:IADV
Username: marley
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
поискать в репо что-нибудь
docker search centos
взять из репо последнюю версию debian
docker pull debian
взять все версии debian
docker pull -a debian
получить список скачанных images
docker images
docker images --tree
docker images debian
Запустить контейнер и отправить 30 пингов до гугла
docker run -d ubuntu /bin/bash -c "ping 8.8.8.8 -c 30"
Запустить интерактивно контейнер и в контейнере shell
docker run -i -t centos:centos6 /bin/bash
-d - Detached mode (запустится в фоне)
docker run -i -t -d debian
Задать имя, иначе она будет выбрано самостоятельно
docker run -i -t -d --name myDebianServ debian
Запустить команду pwd в контейнере от текущего пользователя и затем удалить контейнер:
docker run --rm --user $(id -u):$(id -g) mysql:5.7 pwd
Примонтировать текущую директорию и посмотреть ее содержимое в контейнере:
docker run -v $(pwd):/tmp/build mysql:5.7 ls -la /tmp/build
Запустить и войти в контейнер, а при выходе удалить его:
docker run -it --rm -w /app -v $(pwd):/app -v $HOME/.ssh:/home/appuser/.ssh:ro -u appuser mysql:5.7 bash
Создание тома в памяти с именем foo
и размером 100 мегабайт и uid
размером 1000:
docker volume create --driver local \
--opt type=tmpfs \
--opt device=tmpfs \
--opt o=size=100m,uid=1000 \
foo
и подключение к контейнеру с значением 1770
, чтобы том не был доступен для чтения внутри контейнера:
docker run -d \
-it \
--name tmptest \
--mount type=tmpfs,destination=/app,tmpfs-mode=1770 \
nginx:latest
Создание удаленной директории /home/test
в качестве тома:
docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
sshvolume
Запустить и войти в контейнер, при этом отключив энтрипоинт:
docker run -it --rm --entrypoint="" registry.site.ru/my-nginx:5195318305c sh
Удаление контейнера игнорируя код возврата:
# stop container elasticsearch (silently)
docker rm -f my_container_name || true
Контейнеры и образы хранятся здесь
cat /var/lib/docker/aufs/diff/<container_id>
ls -l /var/lib/docker/containers
ls -l /var/lib/docker/containers | wc -l
показать активные контейнеры
docker ps
показать все контейнеры в том числе остановленные
docker ps -a
Последний стартовавший контейнер.
docker ps -l
Удалить все контейнеры (не образы), которые сейчас не запущены:
docker container prune --force
Старт / стоп
docker start <container_id>
docker stop <container_id>
docker kill <container_id>
docker restart <container_id>
Изменение политики перезапуска контейнера (возможные значения):
docker update --restart=always -d your_image
Вот так можно отменить автозапуск редиса:
docker update --restart no redis
всего опций:
Сколько жрет ресурсов
docker stats <container_id>
docker top <container_id> -ef
Отключиться от контейнера docker без его остановки:
CTRL + P + Q
Подключиться
docker attach <container_id>
Подключиться еще одной сессией к контейнеру
docker exec -it <container_id> bash
docker top <container_id>
docker inspect <container_id>
docker logs <container_id>
Показать какие порты локальной машины соответствуют портам контейнера
docker port <container_id>
Пример
docker port my_container
1337/tcp -> 0.0.0.0:1337
3000/tcp -> 0.0.0.0:3000
8080/tcp -> 0.0.0.0:80
9000/tcp -> 0.0.0.0:9000
узнать IP контейнера Docker
docker inspect --format='' containerId
Удалить контейнер
docker rm <container_id>
docker rm -f <container_id>
stop all Docker containers:
docker stop $(docker ps -a -q)
remove all Docker containers:
docker rm $(docker ps -a -q)
Удаляем образы, которые сейчас не запущены:
docker image prune --all --force
remove all Docker images:
docker rmi $(docker images -q)
удалить volumes:
docker system prune -af && docker image prune -af && docker system prune -af --volumes && docker system df
Получить информацию о слоях image
docker history <image_name>
docker history --no-trunc <image_name>
Создать свой образ lebnik/ansible согласно файла ./docker/Dockerfile:
docker build -t lebnik/ansible ./docker
или с указанием пути к файлу:
docker build -t lebnik/ansible:latest -f ./my/Dockerfile ./my
где ./my это контекст который монтируется в Dockerfile (контекст не обязан содержать Dockerfile). Т.к. контекст это не примонтированная директория, то чтобы работать с директориями/файлами контекста в докер-образе, директорию нужно скопировать из контекста в докер-образ, например скопируем ./my/folder в /tmp/project:
ADD ./folder /tmp/project
или скопируем все содержимое директории ./my в директорию /app
COPY . /app
Инструкции COPY и ADD одинаковы, но ADD умеет немного больше.
Копирование из какого-то образа в образ, который будем собирать:
# сначала объявляем, что при сборке будем использовать какой-то образ
FROM my_files_image as my_files
# последней FROM строкой объявляем на основании какого образа будем делать новый образ
FROM nginx:1.19.10-alpine
COPY --from=my_files /from/dir /to/dir
Если нужно прокинуть $SSH_AUTH_SOCK то всего лишь нужно добавить "--ssh default"
docker build --ssh default -t lebnik/ansible:latest -f ./my/Dockerfile ./my
насколько я понял, можно указать default=$SSH_AUTH_SOCK
Запустить и открыть порты локально
docker run -it --rm --net=host -v $SSH_AUTH_SOCK:/ssh-agent-sock --env SSH_AUTH_SOCK=/ssh-agent-sock my/img:latest bash
Проверить: а если при docker build
указав --ssh default
все равно не хватает прав, то в самом верху Dockerfile добавляют:
# syntax=docker/dockerfile:1
а при выполнении команды указывают:
RUN --mount=type=ssh set -xe && composer install
В докере можно задавать цели сборки и после собирать согласно указанной цели:
FROM nginx:1.19.6-alpine as prod
COPY ./docker-files/prod/nginx/nginx.conf /etc/nginx/nginx.conf
# перенаправление логов в потоки stdout,stderr
RUN ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log
FROM prod as dev
# Prod nginx использует localhost чтобы обратиться к php-fpm, а docker-compose использует php-fpm поэтому так:
RUN sed -i 's|localhost|php-fpm|g' /etc/nginx/nginx.conf
Теперь сборка с указание цели:
docker build -t lebnik/nginx -f ./my/Dockerfile . --target prod
Однако, практика показала, что докер иногда игнорирует указание цели и выполняет все команды указанные в ./my/Dockerfile (делает больше чем мы просим). С чем это связано я пока не понял, но решил опцию --target
пока не использовать.
Не помогает: DOCKER_BUILDKIT=1 docker build ... + нотация # syntax=docker/dockerfile:1
в первой строке ./my/Dockerfile
Иногда это нужно, например чтобы скопировать файлы из контейнера php-fpm в nginx:
ARG PHP_FPM_IMAGE=php7
FROM $PHP_FPM_IMAGE as php-fpm
FROM nginx:1.19.6-alpine
# как таковой сам файл index.php нам не важен, но нам важна статика в директории /app/public
COPY --from=php-fpm /app/public /app/public
Как видно в примере выше, был использовано указание ARG с значением по-умолчанию PHP_FPM_IMAGE
, которое можно переопределить при сборке образа, например так:
docker build -t lebnik/nginx --build-arg "PHP_FPM_IMAGE=php8" .
IF на основе аргумента:
RUN case "$PHP_VERSION" in ( "8"* ) install-php-extensions xdebug;; ( * ) install-php-extensions xdebug-3.1.5;; esac
По-умолчанию, docker использует драйвер логирования под названием: json-file Давайте узнаем путь файла, куда логируются данные
docker inspect logging-01 | grep LogPath
вывод:
"LogPath": "/var/lib/docker/containers/e5a8df3f41f0b308eb0ca057d6bc9e2d/e5a8df3f493bb94ed705cd7ea375655d4a53e-json.log",
А теперь можно настроить ротацию логов, получается путь такой:
/var/lib/docker/containers/*/*.log
p.s. а еще логи еще можно тегировать
Пример:
docker build -t my-built/my-image:latest ./docker/php
docker save -o /tmp/my-image.tar my-built/my-image:latest
scp /tmp/my-image.tar my@remote-machine:/tmp
ssh my@remote-machine
docker load -i /tmp/my-image.tar
docker run --add-host="localhost:192.168.2.XX"
Сразу оговорюсь, из-за разных условий localhost всегда смотрит на 127.0.0.1, но др. имена прекрасно работают.
docker run --add-host=host.docker.internal:host-gateway
Теперь если внутри контейнера обратиться к домену host.docker.internal
то запрос уйдет на IP-адрес машины, на которой запущен докер (спасибо host-gateway).
containerA
в containerB
Конечно можно копировать с помощью монтирования директории и выполнения команды cp внутри контейнера, а можно так:
docker run --rm -d --name containerA php-8.1-fpm-alpine-dev:3.2.2
docker cp containerA:/usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so xdebug.so
docker cp xdebug.so containerB:/usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so
docker rm -f containerA
Инструкция CMD позволяет вам установить команду по умолчанию , которая будет выполняться только при запуске контейнера без указания команды. Если контейнер Docker запускается с командой, команда по умолчанию будет проигнорирована. Если Dockerfile содержит более одной инструкции CMD, все инструкции CMD, кроме последней, игнорируются.
CMD имеет три формы:
CMD ["executable","param1","param2"]
(форма exec, предпочтительно)CMD ["param1","param2"]
(устанавливает дополнительные параметры по умолчанию для ENTRYPOINT в форме exec )CMD command param1 param2
(форма оболочки)Опять же, первая и третья формы были объяснены в разделе форм Shell и Exec . Второй используется вместе с инструкцией ENTRYPOINT в форме exec . Он устанавливает параметры по умолчанию, которые будут добавлены после параметров ENTRYPOINT, если контейнер запускается без аргументов командной строки. См. Например, ENTRYPOINT.
Давайте посмотрим, как работает инструкция CMD. Следующий фрагмент в Dockerfile
CMD echo "Hello world"
когда контейнер запускается, как docker run -it <image>
будет производить вывод
Hello world
но когда контейнер запускается с командой, например docker run -it <image> /bin/bash
, CMD игнорируется и вместо этого запускается интерпретатор bash:
root@7de4bed89922:/#
Инструкция ENTRYPOINT позволяет вам настроить контейнер, который будет работать как исполняемый файл. Он похож на CMD, поскольку также позволяет указывать команду с параметрами. Разница в том, что команда ENTRYPOINT и параметры не игнорируются, когда контейнер Docker запускается с параметрами командной строки. (Есть способ игнорировать ENTTRYPOINT, но вряд ли вы это сделаете.)
ENTRYPOINT имеет две формы:
ENTRYPOINT ["executable", "param1", "param2"]
(форма exec, предпочтительно)ENTRYPOINT command param1 param2
(форма оболочки)Будьте очень осторожны при выборе формы ENTRYPOINT, потому что поведение форм значительно отличается.
Форма Exec ENTRYPOINT позволяет вам устанавливать команды и параметры, а затем использовать любую форму CMD для установки дополнительных параметров, которые с большей вероятностью будут изменены. Аргументы ENTRYPOINT используются всегда, в то время как аргументы CMD могут быть перезаписаны аргументами командной строки, предоставленными при запуске контейнера Docker. Например, следующий фрагмент в Dockerfile
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
когда контейнер запускается, как docker run -it <image>
будет производить вывод
Hello world
но когда контейнер запускается, docker run -it <image> John
это приведет к
Hello John
Форма оболочки ENTRYPOINT игнорирует любые аргументы командной строки CMD или docker run.
docker run -d --name my_nginx nginx
docker exec my_nginx sed -i 's/localhost/my_host/' /etc/nginx/nginx.conf
docker commit -p --author lebnik my_nginx new_nginx
docker rm -f my_nginx || true
docker run -d --name new_nginx nginx
Запуск контейнера в собственной сети my-network-1
с собственным именем my-postgres
:
docker network create my-network-1
docker run --rm -d --net=my-network-1 --net-alias=my-postgres \
-e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres postgres:9.6-alpine
# если надо, удалим сеть:
docker network rm my-network-1 || true
Часто причиной проблем с сетью является конфликт диапазонов IP адресов, например, VPN подсеть пересекается с подсетью докера. Решается проблема изменением диапазона IP адресов для докера. Для этого нужно в конфиге демона докера /etc/docker/daemon.json указать следующее:
{
"default-address-pools": [
{"base": "10.10.0.0/16", "size": 24}
]
}
Источники: 1 - 2 - 3 - 4 - 5 - 6 - 7