☰ Оглавление

Пример использования docker

Рассказывать про все команды Dockerfile и все опции docker нет никакого смысла — на это есть документация на официальном сайте. Однако, хочется рассказать про небольшое количество самых полезны в быту опций и возможностей.

Давайте, я опишу решение вполне бытовой задачи: я решил пройти курсы по ruby. Ставить в систему всё необходимое я не хочу. По многим причинам: я не уверен, что ruby мне понадобится для чего-то кроме выполнения заданий по курсам (не хочется захламлять систему); возможно, выяснится, что нужны какие-то определённые версии (не хочется захламлять систему и мучиться с даунрейдами); наверняка захочется покопаться с стандартных библиотеках, наставлять туда дебага, хочется иметь возможность легко и гарантированно восстановить всё в первозданном виде.

Я предполагаю, что вы прочитал мою первую заметку про docker

Dockerfile для игр с ruby on rails

Итак, чего мы хотим получить:

Dockerfile получился таким:

FROM ubuntu
RUN apt-get update &&\
    DEBIAN_FRONTEND=noninteractive \
    apt-get install -y \
        sudo \
        screen \
        mc \
        vim \
        ruby \
        ruby-rails \
        sqlite3 \
        curl \
    &&\
    addgroup --system a &&\
    adduser --system --ingroup a --disabled-password a &&\
    \
    echo 'a ALL=(ALL:ALL) NOPASSWD:ALL' >>/etc/sudoers &&\
    \
    echo 'caption always "%{= bb}%{+b w}%n %h %=%t %c"' >>~a/.screenrc &&\
    echo 'hardstatus alwayslastline "%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<"' >>~a/.screenrc &&\
    \
    echo "export PS1='\001\033[32;1m\002[\u \W]\$\001\033[0m\002 '" >>~a/.bashrc &&\
    echo "export LANG=C.utf8" >>~a/.bashrc &&\
    echo "export EDITOR=/usr/bin/vim" >>~a/.bashrc &&\
    echo "export VIEWER=/usr/bin/vim" >>~a/.bashrc &&\
    echo "export PAGER=/usr/bin/less" >>~a/.bashrc &&\
    echo "export LESS=FRSXQ" >>~a/.bashrc &&\
    echo "export LESSCHARSET=utf-8" >>~a/.bashrc &&\
    echo "export GREP_COLORS='fn=36:ms=01;32'" >>~a/.bashrc &&\
    echo "alias ls='ls --color=auto'" >>~a/.bashrc &&\
    \
    echo ". ~/.bashrc" >>~a/.bash_profile &&\
    \
    true
CMD ["su", "-l", "a", "-s", "/bin/bash"]

Что тут есть интересного, на что стоит обратить внимание. Пойдём по прядку.

DEBIAN_FRONTEND=noninteractive очень полезная переменная окружения, которую часто забывают. Она предотвращает любые диалоги с пользователем во время установки пакетов (-y отключает только подтверждение).

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

Дальше ничего необычного:

Здесь вы можете сделать всё, как нравится вам.

Docker команда RUN

Стоит только пояснить, почему всё сделано в одной команде RUN.

Так делать не обязательно. У вас всегда есть выбор из двух опций:

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

Docker команда CMD

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

su -l a -s /bin/bash

Собираем docker-образ

sudo docker build -t ror:latest .

Параметры его получаются примерно такими:

$ sudo docker image ls -a
REPOSITORY   TAG      IMAGE ID       CREATED       SIZE
ror          latest   c96751e9cce9   1 hours ago   342MB

Запускаем docker со средой разработки ruby on rails

Вот тут есть что обсудить:

sudo docker run -it -v /tmp:/home/a/w -p 3000:3000 --name ror-vm ror

Тут есть две полезных опции:

После выполнения этой команды, вы получите shell пользователя (не root) внутри контейнера.

Не забывайте, что если вы произведёте какие-то изменения в контейнере, то они не сохранятся при перезапуске. Чтобы их сохранить, надо или создать новый скорректированный образ командой docker commit, или внести ваши действия в Dockerfile и пересобрать весь образ.

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

Запускаем rails в docker

Итак вы запустили docker на вашем образе, получили shell.

$ cd w
$ rails new firsttest
$ cd firsttest/
$ rails s -b 0.0.0.0

Тут существенно, что

Теперь на вашей хост-системе открываем в браузере URL http://localhost:3000/ и убеждаемся, что всё работает.

Теперь вы можете редактировать файлы проекта и на хост-системе, и в самом docker-контейнере (там для этого есть screen и vim).

Что тут можно улучшить

Вместо su можно использовать инструкцию Docker USER. Единственное, на что надо будет обратить внимание, что shell запускался в login-режиме.

Файлы на внешней файловой системе будут создаваться с правами внутреннего пользователя. Если вы с ними будете работать только из контейнера, то вы этого, скорее всего, не заметите. Но если вы хотите работать с ними и локально, то имеет смысл создать пользователя и группу с теми же цифровыми id, что и в вашей хост-системе. Тут не всё так просто, скорее всего вы получите конфликт номеров групп, а может даже и конфликт uid-ов. Как их решать (и надо ли их решать) — зависит от ваших конкретных задач.

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

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

$ echo ~a
/Users/a
$ x=a
$ echo ~$x
~a

Решаются подобные штуки через eval:

$ eval echo ~$x
/Users/a

Но тут надо не забывать кавычки.

Если вы хотите настроить time zone, добавьте явно:

ln -sf /usr/share/zoneinfo/GMT /etc/localtime &&\

Если вы действительно захотите создавать такой контейнер ради Ruby on rails, и если вы собираетесь использовать vim, вам могут пригодится такие команды:

echo "set ai" >>/etc/vim/vimrc &&\
echo "set nu" >>/etc/vim/vimrc &&\
echo ":autocmd Filetype ruby set sw=2" >>/etc/vim/vimrc &&\
echo ":autocmd Filetype ruby set ts=2" >>/etc/vim/vimrc &&\
echo ":autocmd Filetype ruby set softtabstop=2" >>/etc/vim/vimrc &&\

Успехов!