Запуск chrome в docker
google-chrome in docker
Need to test some latest Chrome version's features? but hestitant to upgrade your main browser to unstable? this chrome-in-docker project can help you
Or build it locally with Dockerfile here
Check what Chrome version is builtin, and tag a version:
The extra get-latest-chrome.sh script here is to get latest versions of Chrome Stable, Beta, or Unstable version, for testing some latest features, here you may modify the Dockerfile to build a different image with each one, while, since the beta and unstable versions are changing fast, may be updating every week or every day, you don't have to rebuild docker images everyday, with this get-latest-chrome.sh and local volume bind, you can run a different container with the same image; that way, within a relatively longer time range you don't have to rebuild the base docker image; the reasons of a same base image can be reused is dependencies of the different channels (stable, beta, or -dev) are most probably the same, or changing much less often; anyway, if there is any problem that stable can run but unstable cannot, you may always have a no-cache rebuild: by docker build --pull --no-cache . to force pull latest ubuntu base and latest Chrome binary packages.
You may test run it one time first to check what's exact version of each Chrome channel:
Then run 3 different containers with the same base docker image:
To connect the chrome in docker, you may either use port mappings, let it call proper iptables to set up proper mappings; or use inspect to find out the ip addresses of each container:
That means the chrome browser's Chrome Debugging Protocol can be accessed by 172.18.0.4:9222
Or, if you use docker port mapping, like:
VNC session listens default on the container's 5900 port, if you figured out the container's IP address (by above inspect command), an VNC session can be opened by your favorite VNC client connect to this ip address, or you may use another -p localport:5900 to set up another port forwarding to be able to use it from a 3rd computer.
Env variables to customize
- the default VNC password is hola ; you may pass additional env var to docker run by -e VNC_PASSWORD=xxx to change to use a different VNC password;
- the default CHROME is /opt/google/chrome/google-chrome , if you use local volume bind to have different chrome versions, you may pass additional env var by -e CHROME=/path/to/chrome or chromium
Docker Image Build Time
The Dockerfile defined process of where as start, it's starting from latest
Ubuntu as base image, then install VNC and some network utilties like curl and socat, xvfb, x11vnc as Graphic layer for Chrome graphical output, xterm as debugging term window supervisor as processes manager, sudo also for debugging, not technically required.
Then add Google-Chrome's apt source and install google-chrome-stable version, and it will handle all runtime dependencies by Chrome; This static version will be packed as part of the docker image, when you're not using local volume bind, this version will be used. It depends how often do you rebuild, but with above ./get-latest-chrome.sh script, you don't have to rebuild very often.
Then add a regular user at 1000:100 for improved security and run all services under this regular user; sudo can be used for debugging. Copying supervisord.conf as definition of process structure; and entry.sh as container entrypoint.
At container spawn time ( docker run . ), it starts from the entrypoint entry.sh there it handles default VNC password hola , and check CHROME environment, set it default to the stable version /opt/google/chrome/google-chrome ;
Then it exec to supervisord to spawn more processes defined in supervisord.conf
Supervisord is the process manager, it spawns 4 processes:
- Xvfb . as X server
- x11vnc . as VNC on top of X Server
- fluxbox as window manager, this is technically not required, any X11 application can directly run on X server, but with a window manager, it's easier for debugging, when need to move window, resize, maximize, and minimize, etc.
- xterm, same for debugging
- start chrome from CHROME environment variable, with --remote-debugging-port=19222 to enable Remote Debugging Protocol
- socat, as a forwarding channel, chrome can only listen on local loopback interface (127.0.0.1); hence not accepting any request from outside so a tcp forwarding tool like socat is necessary here.
Supervisord will respawn any managed processes if it crashed.
Сегодня будем заниматься засовыванием Chrome в Docker контейнер. Я этим занялся, поскольку планирую перенести пакеты, которые не входят основной репозиторий - в контейнеры. Это безопаснее, реже ломается, быстрее в развёртывании и обновлении, не тянет ненужных зависимостей. Плюс интересно приобрести опыт в работе с контейнерами, которые имеют GUI. Chrome хороший, в этом плане, кандидат - много неочевидных нюансов в настройке. Приступим.
В отличии от множества примеров в интернете, я хочу иметь локальное соединение с X11, без использования ssh. Я ленивый и поэтому шрифты, курсоры и прочее должно браться из настроек хостовой машины, а не настраиваться внутри. Запускаться всё это безобразие должно максимально просто, без сложных настроек моей машины.
Bringing together the Dockerfile
Now we can piece together our Docker commands. Make sure to name the file Dockerfile . If you specify a different name, then you will need to explicitly identify it to Docker at build time:
With the Dockerfile complete, we can now build an image. This is done using the docker build command. This command will assume that the Dockerfile is actually named ‘Dockerfile’ and is in the current working directory. It takes two arguments:
- A unique name for the image, referred to as a “tag”
- The path to copy into the “build context”. Be very careful to never specify ‘/’. Doing so will copy your entire machine into the build context!
To build the Docker image, make sure the bootstrap script (named bootstrap.sh ) and the Dockerfile are in the same directory and execute the following command:
After a few minutes, Docker will finish building the image. Running docker images will show you the image name and ID.
Note: If you are looking at my chrome-docker repository, I have automated the build command using an included Gradle project. Building it using Gradle is completely optional; it is only for convenience.
Finally, we can create and run a Docker container from the image. Go ahead and give the following command a try:
This will launch a new Docker container and run Xvfb, Fluxbox, and a VNC server. You can access the container’s display by pointing a VNC client to 127.0.0.1 .
Note: While the VNC_SERVER_PASSWORD argument is optional, it is not if you are using the macOS VNC viewer. If you do not set a password on macOS, you will not be able to connect to the container’s VNC server.
You can now start Chrome by right clicking the desktop and selecting:
You will be prompted to make Chrome your default browser and whether or not analytics should be sent to Google. Once you answer those questions, you will be able to browse the web using Chrome.
Is running Google Chrome this way more secure then just running Google Chrome directly on your system? Even if it is, there are a few concerns that should not be ignored:
- You are accessing the container using VNC. If you are not running a firewall on your machine (or the Docker host), then anyone can potentially watch you browse the web
- Google Chrome requires that the --privileged Docker flag be specified. This disables security labeling for the container
Is it possible to run Google Chrome in a Docker container? Yes! Should you do it for testing? Yes! Should you do it to establish a secure browsing session? You can — just make sure you are running a firewall on your machine.
Most of this code can be reused to run other graphical applications in a Docker container. So, why stop at Google Chrome?
Note: All of the following code can be found in my chrome-docker Git project.
Здесь пойдет речь про эмуляцию, а точнее про инструменты высоклассной, неотличимой эмуляции браузера, способной до мельчайших деталей повторить/воспроизвести действия реального юзверя — клики, движения мыши и прочую канитель в движке chrome. При парсинге в 99.9% эмуляция такого уровня — абсолютно лишнее, а при автоматизации действий юзверей на сайтах в 80% пожалуй тоже лишнее. Так что, если вам нужен парсинг — забудьте об инструментах, о которых пойдет далее речь, и не страдайте херней. Для эффективного парсинга есть куда более продвинутые и менее ресурсоемкие инструменты. Доводилось мне видеть вывод top процессов на сервере, после баранов, парсящих при помощи selenium(ещё один неплохой инструмент эмуляции), всё что ни попадя.
После того как один из моих автоматизированных сервисов, использующий phantomjs, приказал помереть от эмуляционной недосточности (хера-се я диагноз поставил), стало ясно, что пришло время изучить более современные методы эмуляции браузеров. Phantomjs не поддерживается с 2016 года, не имеет поддержки новых версий ECMAscript, и не даёт всех необходимых возможностей для эмуляции.
Одним из таких первоклассных инструментов является библиотека puppeteer на node.js, в которой уже установлен «безголовый» chromium браузер, причем самой новенькой версии и полностью готовый к работе. Достаточно лишь поставить его командой:
И можно пользоваться. Естественно у вас должен быть предварительно установлен Node.js с npm.
Для получения текущих версий указываем нонче — setup_15.x или смотрите на сайте текущие.
А из node скрипта нам достаточно лишь подключаться к уже запущенному chromium браузеру при помощи puppeteer.connect, что работает гораздо шустрее и эффективнее. Для начала поставим Docker, качнем browserless и запустим в контейнере:
docker run - e "TOKEN=you_token" - e "MAX_CONCURRENT_SESSIONS=5" - e "EXIT_ON_HEALTH_FAILURE=true" - e "WORKSPACE_DELETE_EXPIRED=true" - e "WORKSPACE_EXPIRE_DAYS=0" - e "CONNECTION_TIMEOUT=20000" - p 3000 : 3000 -- restart always - d -- name browserless browserless / chrome
Теперь, вместо основного пакета puppeteer с headless браузером внутри, нам достаточно поставить «облегченный» пакет puppeteer-core, который предназначен для подключения к существующему(или удалённому браузеру). И также поставим puppeteer-page-proxy, который позволяет работать с прокси в разных вкладках.
Объяснения
Для практических целей пункта выше достаточно, кому интересно, я объясню что значат скрипты выше.
Установка пакетов в "Dockerfile" вопросов вызывать не должна, "dbus-x11" и "libexif12" явно устанавливаются, потому что chrome без них выдаёт пару лишних warning, но работает и без них.
Работать из под root не рекомендуется, а некоторые программы отказываются это делать, поэтому внутри создаётся пользователь "docker" с уникальными UID и GID. При старте, в "run_chrome" они меняются на те, что используются на хостовой машине, для этого в параметрах запуска передаются HOST_UID и HOST_GID. Теперь кеш и конфиги браузера, которые замаплены на вашу файловую систему будут иметь те же права, что и у вашего пользователя. Мы ведь хотели бесшовной работы.
Что бы подключиться к X11 серверу нужно пробросить в контейнер сокет "tmp.X11-unix" и переменную окружения "DISPLAY". Удалённые подключения к нему по умолчанию не разрешены, что бы обойти проблему, дополнительно даём доступ на чтение "$HOME/.Xauthority", а сеть не виртуализируем (параметр "–net=host" при запуске). В качестве альтернативы можно было разрешить все локальные подключения, выполнив на хосте:
Устройство "/dev/snd" нужно, что бы заработал звук.
Chrome по умолчанию создаёт "песочницы" для некоторых своих дочерних процессов, что бы изолировать их и повысить безопасность. Этакий docker внутри docker получается. Но права на это по умолчанию не выдаются. Можно было бы запустить контейнер с флагом "–privileged", что часто решает проблемы подобного рода. Но более дискретным будет выдать нужные разрешения флагами "–cap-add=SYS_ADMIN" и "--security-opt seccomp:unconfined". Как вариант, можно не давать разрешения и запустить сам chrome с флагом "–no-sandbox", отключающим песочницу, что делать не советуют.
Для того, что бы запускать хром с любимыми курсорами, шрифтами и выставить timezone, добавляем volumes: "/usr/share/icons", "/usr/share/fonts", "/etc/fonts" и "/etc/localtime".
Директорию "/dev/shm" я замапил, поскольку chrome иногда падает, например при открытии google maps, из-за недостаточного размера "/dev/shm" выставленного по умолчанию. Решение нашёл вот тут, там же подробнее описаны симптомы.
Сокет "/var/run/dbus/system_bus_socket" пробрасывать не обязательно, но раз уж хочет chrome работать с dbus, почему бы не дать ему это сделать?
Опция "–log-driver=journald" нужна, что бы логи записывались в "journalctl". По умолчанию они пишутся в отдельный файл и кстати не ротируются, в результате могут занимают много места, если вы редко пересоздаёте контейнер. Посмотреть логи Chrome в journald можно вот так:
Интересно посмотреть на логику скрипта "chrome.sh", он создаёт контейнер только при первом запуске. Это относительно долгая операция. При следующем, когда контейнер уже существует, он запускается командой "docker start chrome", что работает сильно быстрее.
Running a window manager
Now we have a display — but no window manager. A fantastic solution for this is the light-weight Fluxbox window manager. Similar to our Xvfb logic, we can block until Fluxbox is ready by using the wmctrl utility:
Bringing the bootstrap logic together
We can bring our Bash logic together now, along with some minor tweaks:
With the bootstrap script completed, we can focus on actually creating the Docker image. This is accomplished by creating a plain text file named Dockerfile . It instructs Docker what to do when building the image.
Docker images have a selectable starting point. Since Ubuntu supports Chrome out of the box, we will use the ubuntu:trusty image as ours. It is important that we update apt-get too — otherwise, we will not be able to install any new packages:
We will also want to add a user for running Chrome, since running as root is not allowed by Chrome:
Now we can install required tools, including fluxbox , wmctrl , x11vnc , and xvfb . We will also install wget so we can add the Google signing key to apt-get:
Lastly, we need to copy the bootstrap script into the image and tell Docker to run the script when a new container is created from it:
Итоги
В результате у нас получилось самодостаточное приложение, внешне ничем не отличается от явно установленного, но при этом оно работает изолировано от основной системы. Плюс оно не несёт дополнительных зависимостей (ну кроме docker). Получилось похоже на обсуждаемые в последнее время snap-пакеты, появившиеся в Ubuntu. Только куда гибче в настройке.
Если таким образом планируется оборачивать больше одного приложения - вынесите общие зависимости в базовый образ. Это сэкономит место на диске.
Docker стремительно ворвался в мир контейнеров и за пару лет из надстройки над LXC развился в систему запуска, окрестрирования, кластеризации, конфигурирования, поставки и создания контейнеров с программным обеспечением. Он так-же имеет простой интерфейс для контроля над ограничением ресурсов. Основой основ для докера служат linux namespaces, которые позволяют изолировать и виртуализировать ресурсы системы, такие как сеть, процессы, точки монтирования и пользователи. В итоге мы можем запустить любой процесс совершенно изолированно, как от самой системы так и от других контейнеров, в своем уникальном программном окружении, со своей сетью, деревом процессов, файловой системой и сетью. Все это дело работает исключительно поверх линукса, docker for windows, docker for osx — это велосипеды с линуксовской виртуалкой. Поэтому некоторые вещи работать там не будут, а некоторые ток с бубном.
Имея опыт работы с джейлами во FreeBSD, zfs-зонами Solaris, openvz и lxc системами линукс можно с уверенностью заявить, что докер вылечил большинство болячек предшественников, и значительную часть головников админов/девопсов о том, как запустить перевел в плоскость, где запустить). Имея докерфайл, дженкинсфайл, вагрантфайл и анзибл с паппетом дев, опс, девопс теперь имеет в наличии everything as a code. Что позволяет ему воспроизвести с нуля весь стек разработки и поставки в любое время в любой среде.
Звучит круто, с чего мне начать?
Процесс установки бессмысленно описывать, так как разработчики докера слова “просто” и “понятно” понимают буквально, что в итоге выливается в хорошие доки и простые шаги установки. Здесь можно найти доки для любой популярной платформы.
Итак, докер у нас есть и введя docker в консоли мы ужасаемся от списка команд вываленных на экран. Стоит отметить, что с версии 1.13 появился раздел Mangement Commands, куда со временем перетекут все команды, а они в свою очередь будут удалены. А пока например команды docker container run и docker run идентичны.
Большинство опенсорсных проектов сейчас имеют докерфайлы и уже готовые докер-имейджи. Разработчику нет необходимости устанавливать на свою машину mysql/postgres/redis/mongo/apache/python/nodejs/php итд — все необходимые версии софта упакованы разрабами в официальне образы. Для примера запустим nginx:
Данная команда скачает latest имейдж с офиц репо nginx на докерхаб, создаст и запустит контейнер с nginx(по сути docker run — это комбинация команд docker pull, docker create, docker start и docker attach). В соседней консоли наберем команду docker ps
Здесь мы видим, что у нас запущен один контейнер с обазом nginx. И по сути от нашей команды docker run больше никакой пользы и нет. Чтобы убить контейнер нужно ввести команду docker kill . Чтобы увидеть помимо запущенных и потушенные контейнеры — можно набрать docker ps -a:
Наигрались и удалили контейнер совсем.
Немного добавим параметров в запуск контейнера:
Иногда приходится цепляться к уже работающему контейнеру, проверять наличие необходимого контента или доустанавливать какие-либо тулзы, для этих целей мы юзаем команду:
Так мы открываем интерактивную псевдо-tty консоль( -ti ) а запускаем там bash. И можем установить необходимый софт, который будет доступен на время жизни контейнера:
Чтобы контейнер с nginx стал еще полезнее, пусть он отдает нашу статику:
Таким образом мы монтируем папку /static/content в контейнер с nginx. Аналогично можно примонтировать в контейнер кастомные конфиги в папку /etc/nginx контейнера. В качестве источника можно указать другой контейнер.
Полный список команд докера и их параметров можно посмотреть тут.
Как я уже писал выше, по дефолту docker качает latest таг имейджа, если необходимо указать конкретную версию, это делается через двоеточие например latest версия nginx на базе alpine-linux будет выглядеть как nginx:alpine. Доступные и поддерживаемые версии лучше всего смотреть на официальных страничках докерхаба и стора.
Увлекательно, но мало!
Попробуем разобрать более сложный вариант — мы разрабатываем тему для wordpress и нам необходимо его быстро развернуть у себя локально. Инсталлить пых как модуль апача или фпм, инсталлить мускуль, это все настраивать, а если несколько тем — носиться с вхостами, отдельными бд итд уныло и утомительно. Поэтому идем на офиц странички wordpress и mysql, изучаем, выбираем версии и вперед.
Работать мы будем из корня проекта, тема наша лежит в папке themes/mytheme.
Запускаем базу данных:
По умолчанию пользователь будет root, а через переменную окружения мы задаем пароль
Запускаем Вордпресс, коннектим его к бд и монтируем в контейнер нашу тему:
docker-compose
После простой инсталляции перейдем сразу к предыдущему примеру и перенесем его в docker-compose.yml. Данный файл описывает наши сервисы и контейнеры, параметры запуска итд. На текущий момент существует уже 3.1 версия формата. каждый ямл файл должен начинаться с версии. По умолчанию docker-compose ищет docker-compose.yml в текущей дире, через параметр -f можно указать любой другой файл или перечислить все файл, если их несколько.
Касательно версий, то если грубо — version: “1” — это простое описание команд запуска докер контейнеров в ямл формате. В version: “2” добавилось понятие сервисов, теперь контейнеры можно скейлить, так-же добавилась секция с описанием вольюмов и сетей и их драйверов. По умолчанию, если сеть не задана, docker-compose при запуске создает новый бридж и коннектит все сервисы к нему, включает резолвер (резовлятся как сервисы, так и отдельные контейнеры). Не нужны линки для взаимосвязи между контейнерами. Version: “3” работает только с docker-engine 1.13+. Данная версия учла кривой опыт doker bundle и реализовала простой и прозрачный деплой в swarm-кластер, в 3.1 запилили поддержку docker secrets. Для сингл хоста за глаза второй версии.
docker-compose.yml:
Данный файл положим в корень проекта(как мы видим docker-compose понимает относительные пути, поэтому мы указали ./themes в описание вольюма с темой). Чтобы запустить наш Вордпресс достаточно набрать команду docker-compose up или docker-compose up -d чтобы запустить в бэкграунде:
Данный файл удобно держать с проектом. Таким образом мы или кто-либо еще всегда смогут поднять проект(в нашем случае проект с темой Вордпресса) на любом компе с докером.
Подчистим за собой:
Напишем более сложный ямл, для Вордпреса docker-compose-staging.yml:
В примере выше мы создали вольюм для базы данных db-mysql и примонтировали его в контейнер с мускулем в /var/lib/myql. Сделали мы это для того, чтобы при пересоздании, рестарте итд — данные сохранялись. Так-же создали две сети: внешняя wp-proxy для соединения сервисов nginx и wordpress и внутреннюю wp-db для коннекта сервиса водпресс с базой данных. Для сервиса Вордпресс помимо темы, мы создали два вольюма, для того чтобы заперсистить плагины и аплоад. Теперь при пересоздании контейнеров бд и Вордпресса все наши данные будут сохранятся, так как мы вынесли их из контейнеров.
В качестве прокси мы заюзали имейдж jwilder/nginx-proxy, который слушает сокет докера, и если находит переменную окружения VIRTUAL_HOST — создает указанный виртуалхост у себя в конфигах с проксированием на контейнер, где прописана эта переменная. Если контейнер экспозит несколько портов, надо указать так-же и VIRTUAL_PORT, куда будет проксироваться трафик.
Запустим наше творение:
В /etc/hosts укажем
Теперь самое интересное, т.к. у нас все изменяемые данные Вордпресса вынесены наружу, мы можем без боязни его скейлить:
А секция upstream в nginx примет вид:
Помимо этого, в пределах сети wp-proxy оба контейнера доступны по названию сервиса wp. А в версии 3 докер-композа мы можем провернуть тоже самое в swarm-кластере.
В итоге без какого-либо напряга мы создали масштабируемый сервис на Вордпрессе.
Убедил, хочу заиметь свой контейнер!
Для начала сделаем шаг назад — а что такое контейнеры? Обычному человеку при слове контейнер на ум может придти 20и тонник. Это прочный объект, который выдерживает нагрузку во время хранения, погрузки и транспортировки и защищают содержимое, находящееся внутри. В голове так-же может возникнуть картинка с портовым доком, где стоят тысячи контейнеров в рядах, составленные друг на друга. Большая часть мерчанта поставляется в таких контейнерах: они прочны, стандартны, их легко хранить и транспортировать. Основная часть людей, задействованная в поставке не имеет представления что находится внутри, для поставки это не имеет значения. Идея софтварных контейнеров аналогична — это неизменные изолированные образы с ПО, функционал которых доступен чаще всего через вызовы api. Это современное решение для надежного запуска ПО (почти) в любом окружении, будь то комп разработчика, тестовые сервера или продакшн кластер. Не важно где — результат запуска всегда будет неизменным.
Поскольку поведение предсказуемо и неизменно независимо от среды, то самый упоротый диалог на свете наконец уходит в небытие:
QA: не работает n’ный функционал на проде.
Dev: но у меня на компе все ок!
В терминологии докер: контейнер — это запущенный образ. Что из себя представляет изнутри сам образ, советую прочитать эту статью. Если грубо, то докеровский имейдж — это стопка более мелких имеджей, каждый из которых содержит файлы, команды, результат их выполнения и другую мета-инфу. Потом драйвер overlay при запуске все это собирает в заданном порядке и из контейнера это выглядит как цельная единая система. Помимо этого, при старте контейнера поверх всего создается новый слой/имейдж. При удалении контейнера по сути только этот слой и удаляется со всеми изменениями произошедшими во время жизни контейнера, однако их можно “закоммитить” создав новый образ.
Текстовым представлением докеровского образа является Dockerfile. При команде docker build этот файл считывается, каждая строка-команда запускает новый контейнер, а ее результат коммитится в новый слой/имейдж. Далее рассмотрим простой пример и все станет понятно. Для этого склонируем проект:
Проект не мой, я просто его форкнул, немного подправил и добавил Dockerfile:
Каждый Dockefile начинается с команды FROM, так мы объявляем, какой базовый имейдж мы будем использовать. Далее может быть указан MAINTAINER, это просто служебная инфа о том, кто во этом всем виноват. В моем случае за базовый имейдж я взял python:2.7-alpine. после чего идут команды RUN. По сути это инструкция, что нужно выполнить внутри имейджа и закоммитить в новый слой. Если с первой командой все более-менее понятно, то второй RUN выглядит мягко говоря по уродски, ее можно было бы переписать так:
Однако, необходимо помнить, что каждое успешное завершение команды ведет к созданию нового слоя, который записывается поверх предыдущих. Соответственно мы установили пачку пакетов, в тмп склонировали проект, а после установки почистили /tmp и удалили ненужные пакеты. Последние два слоя пометят файлы как удаленные, но сами слои не удалят, а запишутся поверх. В итоге у нас и место не очистится, и файлов в контейнере не будет. Собрав первый Dockerfile мы получим имейдж размером 94Mb, собрав второй, работающий точно так-же — 261Mb. Соответственно при написании докерфайлов всегда следует держать баланс между читаемостью и экономией места, особенно для прода, и по возможности объединять в oneliners команды инсталляции, деинсталляции и удаления, чтобы все это выполнялось в рамках одного слоя.
Помимо RUN есть еще команды COPY ADD CMD и другие. COPY копирует файлы из текущего контекста системы в имейдж по указанному пути. Следует помнить, что команда COPY /etc /etc не скопирует /etc/ системы в имейдж, корнем для команды будет директория, которая указана в контексте билда имейджа. Команда ADD аналогична COPY за тем исключением, что понимает урлы и архивы. CMD — команда, которую следует выполнить при запуске контейнера(ее можно определить/переопределить и при старте).
Как уже писал выше, за основу моего имейджа был взят python:2.7-alpine. Это официальный имейдж питона версии 2.7 на базе легковесного дистрибутива linux alpine. В качестве сборки мелких имеджей alpine — лучший выбор, однако следует помнить, что за основу здесь взята сишная либа musl и пока не каждый софт скомпиллится и заработает в alpine.
На проде мы используем debian, как базовый образ, несмотря на то, что весит он больше 120Mb против 4Mb у alpine. Это не проблема, т.к. этот слой копируется только один раз, а все остальные имейджи будут использовать локальную копию. Помимо этого, дебиан надежен и предсказуем, и по умолчанию в нем есть все необходимое.
Но для мелких тулз alpine подходит лучше всего. Самый первый исходный образ — scratch. По сути не содержит ничего. Его можно использовать для гошных бинарников. однако следует не забывать, что необходимо скопировать туда корневые ссл сертификаты и необходимые либы, которые покажет ldd. Советую почитать так-же, что пишут сами докеровцы о докерфайлах. Так-же отличным примером различных техник служат официальные докерфайлы Вордпресс, мускуль, пхп, го, питон, редис итд.
Чтобы собрать наш имейдж необходимо в директории проекта выполнить команду
В качестве имени имейджа мы указали bamboo-build-tools (можно указать несколько), а в качестве контекста для команд COPY и ADD точкой текущую диру. По умолчанию docker build ищет Dockerfile, однако через -f можно указать любой другой файл, аналогично и с контекстом — можно указать любой другой путь.
Еще один головняк для девелопера?
Пробежав галопом и не углубляясь в детали, наверняка сложилось двоякое впечатление. С одной стороны, это все интересно и местами очень полезно, а с другой, возможно остались сомнения — зачем это надо разработчику, ведь он может просто продолжать разрабатывать так, как привык и не тратить время на изучение докера, им пусть балуются опсы. Однако при всех возможных издержках, которые можно насочинять плюсов от использования докера неоспоримо больше, вот некоторые:
H ave you ever wanted to run Google Chrome headlessly without installing it on your system? If not, there are a few reasons to give it a try. Maybe you want to create a throw-away web session without spinning up a full virtual machine. Or, maybe you need to run tests on a web application.
This is where tools like Docker really shine. Creating a Docker image and templating containers from it is resource-light and fast. Docker images are also easily reproducible, and can make achieving “infrastructure as code” a feasible reality.
Let’s give it a shot.
Note: All of the following code can be found in my chrome-docker Git project.
To run a Docker container, we will need a Docker image. An image is a pre-built bundle that contains all of the files and software needed to do the work you are setting out to do. In our case, the Docker image will need to contain:
- A basic Bash script (referred to as a ‘bootstrap’ script herein) that will run our startup logic whenever a new container is created from the image
- Software required to create a “virtual” display to view Google Chrome
- Google Chrome
Since creating a virtual display is not unique to Docker, we can start there and figure out our dependencies along the way.
By default, a Docker container does nothing when it is started. To actually do something, we will need to execute some logic whenever a new container is created from the image. Before we build the Docker image, let’s consider what we will need to run a graphical application:
- A X server
- A window manager
- A means to access the container’s display
No display? No fear!
Our first major challenge is the lack of display. This is where Xvfb (X Virtual FrameBuffer) comes in very helpful. Per its man page:
Xvfb is an X server that can run on machines with no display hardware and no physical input devices. It emulates a dumb framebuffer using virtual memory.
Since all of our container’s startup logic will need to run in a single script, we will need to start Xvfb in the background. Something to keep in mind when running anything in the background (Bash background job, or not) is whether or not subsequent operations will need to wait until the first background operation reaches a certain state. In our case, we need our X server to be fully up and running before starting a window manager.
Using the xdpyinfo utility, we can block until the X server is ready. Let’s put it all into a Bash function:
Accessing the virtual display
We will need a way to access the display. A creative solution is to use a VNC server. This can be especially helpful for debugging a container running on a remote system. At this point in the script, we will want to keep the Docker container running as long as the VNC server stays alive:
Производительность
Десяток секунд занимает только первый запуск, как я сказал выше. Последующие - отрабатывают почти мгновенно. Производительность работы самого chrome - не отличается от нативно установленного. Я проверял при помощи вот этого теста, разница была 0.3% - на уровне погрешности.
Настройка
Сначала тезисно расскажу что нужно сделать, а ниже объясню что эти заклинания значат. Добавьте текущего пользователя в группу "docker", что бы работать с docker без sudo, это удобнее и инструкции ниже даны в расчёте на это предположение.
Создаем файл "Dockerfile" вот с таким содержимым
Читайте также: