grishka / Smithereen

Federated, ActivityPub-compatible social network server with friends, walls, and groups.
The Unlicense
393 stars 31 forks source link

Dockerfile #4

Closed handlerug closed 4 years ago

handlerug commented 4 years ago

This is my take on dockerizing Smithereen. I've included docker-compose.yml example in README.md which works flawlessly for me. What do you think? There are probably grammar errors in documentation because pls sorry for my bad english :)

handlerug commented 4 years ago

By the way, there are some solutions for "building application with Dockerfile" problem:

To be honest I don't think that Dockerfile with build commands is a problem. If you want to customize the image you can push out your image to Docker Registry so users will be able to make another image based on the vanilla image (just make from smithereen the first line of your Dockerfile). If you're afraid of heavy load of compilation process — well, that's not going to be worse than the current approach (which requires you to build it anyway).

cc @grishka

grishka commented 4 years ago

Well, I was going to start publishing binary releases at some point when it's mature enough to be installed somewhere for actual serious use as opposed to experimentation.

One of my friends who's more experienced with Docker than I am, @marinintim, told me that there's a way of bootstrapping by building the binaries in a separate container and then deploying them to a new one that will actually run in production. I don't know a thing about Docker but this feels very much sensible. Only thing I'm doubtful about is updating.

handlerug commented 4 years ago

Yeah, that way is similar to my suggested approach of building binaries inside GitHub Actions pipeline. I don't think Docker will be useful for building them (because there is already a pipeline for building .jar and jni), but they can be put inside Docker image with something like:

FROM maven:3-jdk-11

EXPOSE 4567

WORKDIR /usr/local/app
COPY libvips_jni.so jni/
COPY target/smithereen-jar-with-dependencies.jar .

ENTRYPOINT java -Djava.library.path=/usr/local/app/jni -jar /usr/local/app/smithereen-jar-with-dependencies.jar /usr/local/etc/config.properties

Then we could build this image with docker build -t smithereen:commit-hash . and push it out to Docker registry (I think?) so users could use it just by referencing its name in Docker Compose or docker run. But this project may be not mature enough for publishing its images on registry.docker.com 🤔 Docker can export images as .tar archives (docker export -o image.tar smithereen:commit-hash && docker load -i image.tar) but that looks dirty.

What do you mean by "updating"? If you want to update binaries, you can just swap images (but be sure to update config and stuff). Database schema updates can be done by docker exec but... that's not really good way of updating database. Ideally, application would do DB migrations by itself on startup. But it's actually not that important now, considering that this project has not reached usability state (as you say), so there's no reason to worry about it now :D

grishka commented 4 years ago

What do you mean by "updating"?

I mean updating the binaries to newer releases while keeping the database and user-uploaded files. On my dedicated server I do this by pushing the new jar using scp and then running service smithereen restart. Again not sure if you're supposed to replace files like that inside docker containers.

Ideally, application would do DB migrations by itself on startup.

That's something I'm going to have when there are other people running this thing on their servers. Again, it's too early of a version to do this now.

handlerug commented 4 years ago

I mean updating the binaries to newer releases while keeping the database and user-uploaded files.

If you use docker-compose, you don't need to do anything — the example from README.md from my pull request does the thing. These lines make configuration, files and cache persistent, and these lines make the database persistent.

Again not sure if you're supposed to replace files like that inside docker containers.

It doesn't replace files (I think replacing files is a bad practice? I'm not an expert in Docker ¯\_(ツ)_/¯). /host/path:/container/path just mounts /host/path from your host machine to /container/path in the container (so files are persistent and stored on the host machine), so everything just works.

grishka commented 4 years ago

Так. Я, оказывается, вообще не понимал, как это работает. Там основная идея, как я (теперь) понимаю, в том, что есть образы контейнеров (docker image), которые доступны только на чтение, а финальная штука собирается из них + добавляется какой-то кусок файловой системы, доступный на запись, и хранящийся отдельно. Типа, одна виртуалка с самим сервером, и ещё одна — с mysql, и они общаются по внутренней сети. Только это не совсем виртуалки, потому что они используют ядро ОС хоста. Поэтому для обновления надо просто пересобрать образ и заменить старый новым, а данные и так хранятся отдельно.

Кстати, а что у меня в дампе БД такого, что современный mysql его не понимает?

handlerug commented 4 years ago

Да, в изоляции приложений как отдельные "чёрные ящики" и есть преимущество докера. Такие ящики довольно удобно разворачивать и масштабировать приложение в пару команд, с помощью тех же docker-compose или Kubernetes (не то, чтобы я этим занимаюсь, но всё равно интересная вещь).

Кстати, а что у меня в дампе БД такого, что современный mysql его не понимает?

Ну, в этом дампе из Sequel Pro надо удалять строчку с SET SESSION SQL_MODE в конце, а то новая MySQL на ней выкидывает ошибку. К слову, Sequel Pro не умеет в новые версии MySQL и просто крашится...

grishka commented 4 years ago

Я вот ещё что не понимаю — а откуда конфиг берётся в контейнере? В частности, оно же из него данные для подключения к БД берёт.

grishka commented 4 years ago

А так в принципе я бы смержил и сам допилил. Соберу JNI-библиотеку под все нужные разновидности ОС, чтобы не надо было её собирать локально, сделаю нормальную инициализацию базы (чтобы аккаунт админа создавался при установке), вот это всё.

handlerug commented 4 years ago

Я вот ещё что не понимаю — а откуда конфиг берётся в контейнере? В частности, оно же из него данные для подключения к БД берёт.

86 строка в README.md, там строчка из примера конфига docker-compose — config.properties монтируется из текущей директории в ФС контейнера. Это уже задача того, кто будет разворачивать инстанс.

grishka commented 4 years ago

Ага, вижу. Но там же в 96 строчке задаются пользователь и пароль для mysql 🤔 Было бы логично их подставлять в конфиг и было бы странно если бы было нельзя использовать в этих захардкоженных файлах переменные. Короче, попробую разобраться)

handlerug commented 4 years ago

Ну это уже за администратором — в конфиг можно подставлять переменные окружения, подавать их нужно в команду docker-compose, дальше их можно передать внутрь контейнера через env... Сам файл не захардкожен, захардкожен только путь до него внутри контейнера (в команде запуска в докерфайле).

grishka commented 4 years ago

Ну мне прост хочется чтобы не надо было никакие конфиги вообще редактировать, чтобы запустил одну команду, а дальше оно само :)

handlerug commented 4 years ago

Дело в том, что юзернейм и пароль суперюзера БД нужно передать как и в контейнер БД, так и в контейнер Smithereen. Поэтому их нужно указывать в двух местах. Можно сделать поддержку env variables, каждому контейнеру передать $DB_USER и $DB_PASS и потом запускать этот комбайн через DB_USER=root DB_PASS= docker-compose up ..., но ИМХО этот подход неудобен, ибо нужно либо постоянно передавать докер-компоусу переменные или городить какую-либо отдельную конфигурацию/скрипт.

Юзеру всё равно придется скопировать и настроить config.properties для себя: у всех разные конфигурации веб-сервера/реверс-прокси, кто-то хочет поменять порт, ограничения на размер кешей. Точно также и с docker-compose.yml — вдруг нужно поменять порт? поменять расположение конфигурации? вдруг юзер вообще хочет запустить контейнер с nginx, чтобы одним докером обойтись? настроить docker volume для кэша медиа и аватарок, маунтить конфиг nginx внутрь контейнера, etc? В этом подходе есть некоторые неудобства, но зато всё понятно и никакой магии.

Единственное, что я надумал — закоммитить docker-compose.yml в репозиторий в директорию examples, чтобы было проще в консоли на сервере его cp-нуть и отредачить :D

grishka commented 4 years ago

А если сделать БД через internal сеть, то будет безопасно сделать пароль каким-нибудь захардкоженным и простым?

handlerug commented 4 years ago

Думаю, вполне. docker-compose автоматически настраивает внутреннюю сеть для контейнеров (как минимум, с этим конфигом), поэтому должно работать из коробки. Вряд ли к нему можно будет получить доступ извне, разве что если на самом сервере будут какие-то проблемы с iptables и роутингом 🤔