Docker: курс katacoda, часть #1 – запуск контейнеров

Автор: | 16/09/2016
 

docker_lxcПеревод.

Полный курс (который категорически рекомендую) доступен на katacoda.com тут>>>.

Шаг 1 – запуск контейнера

В Docker все контейнеры запускаются из Docker-образов. Эти образы содержат в себе все необходимое для запуска процесса – хост не требует никакой дополнительной конфигурации.

Что бы запустить контейнер – вы можете собрать его самостоятельно, либо, как предполагается в этом сценарии – использовать уже созданный образ, созданный Docker Inc и сообществом.

Готовые образы можно найти в https://registry.hub.docker.com, либо с помощью команды docker search <image-name>. Например, что бы найти образ Redis – можно использовать команду docker search -s 1 redis:

$ sudo docker search -s 1 redis
[sudo] password for setevoy: 
NAME                      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
redis                     Redis is an open source key-value store th...   2715      [OK]       
sameersbn/redis                                                           35                   [OK]
torusware/speedus-redis   Always updated official Redis docker image...   31                   [OK]
bitnami/redis             Bitnami Redis Docker Image                      25                   [OK]
anapsix/redis             11MB Redis server image over AlpineLinux        6                    [OK]
webhippie/redis           Docker images for redis                         5                    [OK]
williamyeh/redis          Redis image for Docker                          3                    [OK]
clue/redis-benchmark      A minimal docker image to ease running the...   3                    [OK]
unblibraries/redis        Leverages phusion/baseimage to deploy a ba...   2                    [OK]
kampka/redis              A Redis image build from source on top of ...   1                    [OK]
greytip/redis             redis 3.0.3                                     1                    [OK]
servivum/redis            Redis Docker Image                              1                    [OK]
vguardiola/gentoo-redis   Redis server                                    1                    [OK]
miko2u/redis              Redis                                           1                    [OK]

Опция -s 1 тут – указывает на необходимость вывести результаты c минимум +1 рейтинга.

Задача

Требуется запустить один контейнер, фоновым процессом, из официального образа Redis. После того, как образ будет найдет в registry – его можно запустить командой docker run <options> <image-name>. По умолчанию – Docker запускает процесс в интерактивном режиме. Что бы запустить его в фоне – используется опция -d.

Сейчас у вас не будет локальной копии образа, поэтому он будет загружен из Docker-репозитория. При повторном запуске – будет использоваться локальный образ.

Примечание

У всех контейнеров есть имя и ID для использования в Docker-командах. Вы можете указать своё имя для запускаемого контейнера с помощью опции --name, например – --name redis.

Решение

Находим образ:

$ sudo docker search -s 1 redis
[sudo] password for setevoy: 
NAME                      DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
redis                     Redis is an open source key-value store th...   2715      [OK]       
...

Запускаем, используя -d для запуска в бекграунде, и --name – с именем контейнера:

$ sudo docker run -d --name redis redis:latest
Unable to find image 'redis:latest' locally
latest: Pulling from redis
c289280e4ecc: Pull complete 
...
e2b295164860: Pull complete 
Digest: sha256:9097f82c009bcaa732776da3e2a6b638a32c565a6b00bb55e74d0215c526d3c6
Status: Downloaded newer image for redis:latest
cf363ff9714d2ef17bc05e297d0d8db3043f9e27cd7348fad146b8d97f0db731

Шаг 2 – просмотр запущенных контейнеров

Команда docker ps позволяет получить список всех запущенных в настойщий момент контейнеров с указанием образа, использованого для запуска контейнера.

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

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
cf363ff9714d        redis:latest        "docker-entrypoint.s   24 seconds ago      Up 23 seconds       6379/tcp            redis

Кроме того – это команда выводит имя контйнера и его ID, которые могут быть использованы для получения информации о контейнере.

Команда  docker inspect <friendly-name|container-id> предоставляет еще больше деталей о контейнере, включая его IP, примонтированные разделы, состоянии и т.д:

# docker inspect cf363ff9714d
[{
    "AppArmorProfile": "",
    "Args": [
        "redis-server"
    ],
    "Config": {
        "AttachStderr": false,
        "AttachStdin": false,
        "AttachStdout": false,
        "Cmd": [
            "redis-server"
     ...

Отформатировать вывод можно с помощью jq:

# docker inspect cf363ff9714d | jq '.[0] | {Image: .Image, ExposedPorts: .Config.ExposedPorts, IP: .NetworkSettings.IPAddress}'
{
  "IP": "172.17.0.1",
  "ExposedPorts": {
    "6379/tcp": {}
  },
  "Image": "e2b29516486046b11cda7665fc9ea7c7f4025e280b8e33ade5acd26f78b51ebb"
}

Команда docker logs <friendly-name|container-id> – выведет сообщения, которые контейнер пишет в STDERR и STDOUT:

# docker logs cf363ff9714d
1:C 15 Sep 08:39:17.030 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 3.2.3 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 1
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

1:M 15 Sep 08:39:17.032 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
1:M 15 Sep 08:39:17.032 # Server started, Redis version 3.2.3
1:M 15 Sep 08:39:17.032 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:M 15 Sep 08:39:17.032 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
1:M 15 Sep 08:39:17.032 * The server is now ready to accept connections on port 6379

Шаг 3 – порты

Каждый контейнер является абсолютно независмым от других, и работает изолированно от других контейнеров. Если требуется получить доступ к сервису в контейнере снаружи – вам необходимо открыть порт, который будет привязан к конкретному контейнеру. После привязки порта – вы сможете получить доступ к службе так же, как если бы она работала не в контейнере – а в операционной системе хост-машины.

Указать порты во время запуска контейнера можно с помощью опции -p. Например – сервис Redis отркывает для доступа порт 6379. Если вы хотите привязать этот порт контейнера к хосту – укажите -p 6379:6379.

Задача

Запустите новый контейнер с Redis в фоном режиме, с именем redis и портом хост-машины 6379, привязанном к порту 6379 контейнера.

Примечание

По умолчанию – порт на хосте будет привязан к IP 0.0.0.0, т.е. – всем IP-адресам машины. Вы можете указать точный IP во время указания порта, например - -p 127.0.0.1:6379:6379.

Решение

Получаем IP хоста:

# ip a s | grep eth0 | tail -n 1 | cut -d " " -f 8
10.11.100.255

Запускаем контейнер:

# docker run -d -p 10.11.100.255:6379:6379 --name redis-6379 redis
8064560e8fcaf2f5d899889851ef04a95af82f898f561888c2798ed0a0b32077

Проверяем:

# docker inspect cf363ff9714d | jq '.[0] | {ExposedPorts: .Config.ExposedPorts}'
{
  "ExposedPorts": {
    "6379/tcp": {}
  }
}
# netstat -anp | grep 6379
tcp        0      0 10.11.100.255:6379      0.0.0.0:*               LISTEN      11329/docker-proxy

Шаг 4 – случайные порты

Выше мы рассмотрели как привязать контейнер к определённому порту хоста. Этот подход позволяет с легкостью получить доступ к приложению, но имеет существенный недостаток – таким образом можно запустить только одно приложение.

Одно из преимуществ контейнеров – это то, что вы можете разделить конфигурацию приложения (например – на каком порту контейнера запускать сервис) от настроек хоста (например – какой порт на хост-машине привязать к контейнеру).

Аналогично с привязкой чётко заданного порта – если вы запустите контейнер с опцией -p 6379Docker привяжет случайный порт хоста к этому порту. Это позволяет запускать несколько одинаковых сервисов на одном и том же хосте, без необходимости изменять настройки службы, такие как его локальный порт.

Задача

Запустить Redis как в предыдущей задаче, но дать Docker самому выбрать порт хост-машины.

Вы можете использовать команду docker port redis 6379, что бы узнать привязанный порт хоста. Кроме того – docker ps так же выводит такую информацию.

Решение

Запускаем Redis:

# docker run -d -p 6379 --name redis-random-port redis
e5a53cc4a41c6a336e734a8f2d9d82c7d4af27096d9dc7ace74bd83c033794e4

Проверяем порты:

# docker port redis-random-port 6379
0.0.0.0:32768
# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                     NAMES
e5a53cc4a41c        redis:latest        "docker-entrypoint.s   39 seconds ago      Up 38 seconds       0.0.0.0:32768->6379/tcp   redis-random-port

Шаг 5 – подключение каталогов

Мы уже рассмотрели – как запустить контейнер, и выполнить привязку портов. Следующий шаг – начиться работать с данными в контейнерах.

Конейнеры разработаны так, что бы быть неизменяемыми. Любые данные, которые должны быть сохранены посте остановки контейнера – должны храниться на хост-машине. Это достигается с помощью монтирования каталогов хоста внутрь контейнеров.

Привязка директорий (так же называемых “разделы“, volumes) в Docker схожа с привязкой портов – с помощью опции -v. Когда директория (раздел) примонтирована таким образом к запущенному контейнеру – вы можете получить доступ к файлам в этой директории прямо из этого контейнера, а любые изменения в этих файлах, выполненные из контейнера – будут сохранены на хост-машине. Этот подход позволяет вам изменять или обновлять контейнеры без утраты данных в них.

Задача

Официальный образ redis хранит логи и данные в каталоге /data. Запустите контейнер, который примонтирует каталог /data контейнера к каталогу /home/username/data.

Примечание

В можете использовать переменные, например $PWD - что бы указать текущий каталог.

Решение

Запускаем контейнер (каталог $HOME/data будет создан автоматически, если его нет):

# docker run -d -p 6379 --name redis-mapped-volume -v $HOME/data:/data redis
43ffb6cfcaf20a7f6faae8fe152e0699de58af854cea08bcddcf5d8f63722782

Проверяем каталог:

# ls -l /home/setevoy/data/
total 0

Добавим файл:

# echo "testfile" > /home/setevoy/data/testfile.txt
# cat /home/setevoy/data/testfile.txt
testfile

Проверяем в контейнере:

# docker exec 43ffb6cfcaf cat /data/testfile.txt
testfile

Шаг 6 – запуск контейнера в foreground

Некоторые контейнеры, такие как сервера баз данных, лучше всего запускать в фоновом режиме. Однако Docker не ограничен только запуском таких служб. Контейнеры могут запускать любые службы точно так же, как это можно сделать на самом хосте.

Ранее мы использовали опцию -d, что бы запустить процесс в бекграунде. Без неё – контейнер будут запущен в интерактивном (foreground) режиме.

Если мы хотим взаимодействовать с контейнером (например – полуить доступ к его консоли), вместо того, что бы только видеть его output – добавьте опции -ti.

Кроме того, что контейнеры могут быть запущены в foreground и background режимах – как правило вы можете изменить команду, которая будет выполнена при запуске контейнера (CMD и ENTRYPOINT для Dockerfile мы рассмотрим позже). Например, вы можете запустить Ubuntu и выполнить в ней какую-то системную команду – либо запустить интерпретатор bash.

Пример

Команда docker run ubuntu ps запустит контейнер с Ubuntu и выполнит команду ps для отображения всех процессов в контейнере:

# docker run ubuntu ps
  PID TTY          TIME CMD
    1 ?        00:00:00 ps

Или – можно запустить консоль в контейнере:

# docker run -ti ubuntu 
root@6085fa2ab86b:/# uname -a
Linux 6085fa2ab86b 4.2.0-42-generic #49~14.04.1-Ubuntu SMP Wed Jun 29 20:22:11 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

Продолжение тут.