Опции командной строки docker и их аналоги в docker-compose.yml и Dockerfile

Докер контейнеры можно запускать как с помощью команды docker, так и с помощью docker-compose. Если нужно запустить просто один контейнер, то обычно это делается с помощью команды docker. А вот если нужно запустить целое Приложение, которое состоит из нескольких связанных между собой контейнеров, то для этого удобно использовать docker-compose.

В качестве примера большого приложения которое запускается с помощью docker-compose можно привести какую-нибудь веб систему. Есть контейнер в котором работает база данных, есть контейнер в котором работает backend (из этого контейнера торчит http api), есть контейнер в котором работает фронт (Single Page Application) и есть еще и контейнер с nginx, в который нужно ходить браузером, а этот nginx прокинет некоторые запросы в контейнер с backend, а некоторые в контейнер с фронтом.

У команды docker есть куча опций которое можно передать в командной строке и в docker-compose тоже есть огромное количество настроек.

Тут я собрал те настройки, которые достаточно часто применяются в реальной жизни.

Вот пример запуска контейнера с помощью команды docker:

docker run \
    --detach \
    --name sample \
    -e BASE=asdf \
    --volume `pwd`/src/:/app/src/ \
    --publish 8080:3000 \
    ubuntu:18.04 \
    sleep 1000 \
    ;

После запуска этой команды на экране отобразится ID контейнера и консоль снова готова к новым командам:

$ docker run ...
f9c8f5d31bae86abeedb4499e2ad1c08443bcea83e6df5f68b73048ceb8cf9a7
$

Если посмотреть какие контейнеры запущены, то будет виден контейнер, который мы только что запустили:

$ docker ps -a
CONTAINER ID  IMAGE         COMMAND       CREATED        STATUS        PORTS                   NAMES
f9c8f5d31bae  ubuntu:18.04  "sleep 1000"  6 seconds ago  Up 4 seconds  0.0.0.0:8080->3000/tcp  sample

Из вывода команды видно из какого образа запущен контнере (колонка IMAGE), какая команда запущена (колонка COMMAND), какие порты прокинуты (PORTS) и имя контейнера (NAMES).

Можно проверить что мы установили переменную окружения. Для этого выполним команду в работающем контейнере:

$ docker exec sample env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=f9c8f5d31bae
BASE=asdf
HOME=/root

Здесь видно все переменные окружения, которые установлены, включая BASE, которую мы установили при запуске контейнера.

Вот пример файла docker-compose.yml в котором записаны такие же команды для запуска контейнера:

$ cat docker-compose.yml
backend:
  container_name: sample2
  image: ubuntu:18.04
  environment:
    - BASE=asdf
  ports:
    - "8081:3000"
  volumes:
    - ./src/:/app/src/
  command: sleep 1000

В этом docker-compose.yml указан sample2 в качестве имени и порт на хост машине используется 8081. Это сделано чтобы можно было одновременно запустить все контейнеры, которые указаны в этом тексте.

Запускаем контейнер из yml файла с помощью команды:

$ docker-compose up -d
Recreating sample2 ... done

(-d у docker-compose up это то же что и --detach у команды docker).

И дальше можно проверить что оба контейнера работают и они очень похожи:

$ docker ps -a
CONTAINER ID  IMAGE         COMMAND       CREATED        STATUS        PORTS                   NAMES
b743329a8bc5  ubuntu:18.04  "sleep 1000"  3 minutes ago  Up 3 minutes  0.0.0.0:8081->3000/tcp  sample2
f9c8f5d31bae  ubuntu:18.04  "sleep 1000"  9 minutes ago  Up 9 minutes  0.0.0.0:8080->3000/tcp  sample

Поскольку второй контейнер мы запустили с помощью docker-compose, то мы можем посмотреть информацию о контейнерах с помощью:

$ docker-compose ps
-----------------------------------------------------
 Name      Command     State           Ports
sample2   sleep 1000   Up      0.0.0.0:8081->3000/tcp

Можно собрать свой собственный контейнер и перенести туда некоторые параметры, которые мы указываем при запуске.

$ cat backend/Dockerfile
FROM ubuntu:18.04

ENV BASE=asdf

CMD sleep 1000

$ cat docker-compose.yml
backend:
  build: backend/
  container_name: sample3
  ports:
    - "8082:3000"
  volumes:
    - ./src/:/app/src/

Вот все 3 контейнера (причем тот который был запущен первым уже не работает, так как команда sleep завершилась (1000 секунд это чуть меньше 17 минут)):

$ docker ps -a
CONTAINER ID  IMAGE         COMMAND         CREATED         STATUS                     PORTS                   NAMES
f91a64360c43  d2_backend    "/bin/sh -c 's  3 minutes ago   Up 3 minutes               0.0.0.0:8082->3000/tcp  sample3
b743329a8bc5  ubuntu:18.04  "sleep 1000"    16 minutes ago  Up 16 minutes              0.0.0.0:8081->3000/tcp  sample2
f9c8f5d31bae  ubuntu:18.04  "sleep 1000"    30 minutes ago  Exited (0) 13 minutes ago                          sample

Итого. Вот табличка как называются параметры при запуске docker их командной строки, при использовании docker-compose и в Dockerfile:

docker cli                       docker-compose.yml          Dockerfile
-----------------------------------------------------------------------------
--name sample                    container_name: sample      -

-e BASE=asdf                     environment:                ENV BASE=asdf
                                   - BASE=asdf

--volume `pwd`/src/:/app/src/    volumes:                    -
                                   - ./src/:/app/src/

--publish 8080:3000              ports:                      -
                                   - "8080:3000"

ubuntu:18.04                     image: ubuntu:18.04         FROM ubuntu:18.04

sleep 1000                       command: sleep 1000         CMD sleep 1000

Имя контенера, папки которые в него пробрасываются и связку портов с хост машиной в Dockerfile указать нельзя — и это совершенно логично. Этих данных нет во время сборки образа, они появляются только во время запуска контейнера.

Иван Бессарабов
ivan@bessarabov.ru

6 августа 2019