160 lines
8.4 KiB
Markdown
160 lines
8.4 KiB
Markdown
|
Title: Dockerize all die Sachen
|
||
|
Date: 2015-07-01 12:28
|
||
|
Slug: dockerize-all-die-sachen
|
||
|
Tags: docker, linux
|
||
|
Description: Ich habe mich endlich mal rangemacht um einige Sachen in Docker Container zu packen
|
||
|
|
||
|
|
||
|
Docker ist manchmal immer noch ein Buch mit sieben Siegeln für mich. In meinem Fall war die Lernnkurve nicht gerade die Beste. Aber was solls. Das meiste lernt man dann doch durch Trial and error. Ein paar kleine selbstgeschriebene Web-Apps laufen bei mir schon in Docker Containern nun wollte ich bestehende Dienste auf meinem Heimserver in Container auslagern. Vor allem die Sachen denen ich immer noch ein wenig kritisch gegenüber stehe. Da wären zum Beispiel [Owncloud](https://owncloud.org/), [Plex](http://plex.tv) und [tiny tiny rss](https://tt-rss.org). Was ich gelernt habe: Jede Anwendung fordert individuelle Entscheidungen die manchmal erst auf den zweiten Blick Sinn machen :).
|
||
|
|
||
|
## Owncloud
|
||
|
|
||
|
Meine lokale Owncloud Installation hat schon lange keine Liebe mehr gesehen. Oft benutze ich es nicht mehr und um Updates hatte ich mich auch nicht so wirklich gekümmert. Ich musste mir erstmal Gedanken was ich zum Beispiel mit PHP Anwednungen machen. Bei Python starte ich [Gunicorn](http://gunicorn.org/) im Container und richte einfach einen Reverse-Proxy (Nginx) drauf. Bei PHP brauche ich einen Layer dazwischen. Ich habe mich dafür entschieden einen minimalen Nginx mit php-fpm im Container laufen zu lassen. Davor kommt dann der Reverse Proxy mit SSL und Soße und Scharf. Und da ich php-fpm und Nginx im Container laufen haben muss, muss ich die Prozesse per [Supervisor](http://supervisord.org/) starten. Normalerweise versuche ich die einzelnen Prozesse in verschiedene Container zu packen. Hier habe ich mich explizit dagegen entschieden. Die Config dazu sieht in diesem Fall so aus:
|
||
|
|
||
|
```
|
||
|
[supervisord]
|
||
|
nodaemon = true
|
||
|
|
||
|
[program:nginx]
|
||
|
command = nginx
|
||
|
user = root
|
||
|
autostart = true
|
||
|
|
||
|
[program:php]
|
||
|
command = php5-fpm --nodaemonize
|
||
|
user = root
|
||
|
autostart = true
|
||
|
```
|
||
|
|
||
|
Sehr wichtig ist das Supervisor nicht als daemon läuft. Sonst schließt sich der Docker Container sofort wieder nach dem ausführen. Mein Dockerfile sieht so aus:
|
||
|
|
||
|
```
|
||
|
FROM nginx
|
||
|
|
||
|
RUN apt-get update && apt-get -y install bzip2 curl supervisor php5-fpm php5-gd php5-json php5-mysql php5-curl php5-intl php5-mcrypt php5-imagick php5-sqlite
|
||
|
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||
|
|
||
|
RUN mkdir -p /var/log/supervisor
|
||
|
RUN mkdir /var/www
|
||
|
|
||
|
RUN curl -k https://download.owncloud.org/community/owncloud-8.0.4.tar.bz2 | tar jx -C /var/www/
|
||
|
RUN chown -Rv www-data:www-data /var/www
|
||
|
|
||
|
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||
|
COPY php.ini /etc/php5/fpm/
|
||
|
COPY nginx.conf /etc/nginx/nginx.conf
|
||
|
|
||
|
VOLUME ["/var/www/owncloud/data", "/var/www/owncloud/config"]
|
||
|
EXPOSE 80
|
||
|
CMD ["/usr/bin/supervisord"]
|
||
|
```
|
||
|
|
||
|
Eigentlich auch nichts wildes. Die Verzeichnisse `/var/www/owncloud/data` und `/var/www/owncloud/config` sind als Volumes deklariert. Die werde ich dann mit lokalen Verzeichnissen auf dem Host verbinden. Alle anderen Files liegen in dem passenden [Repository](https://github.com/xsteadfastx/owncloud_docker).
|
||
|
|
||
|
Grundlegend benutze ich [docker-compose](https://docs.docker.com/compose/). Es macht den Workflow für mich so viel besser. Ich schreibe in `docker-compose.yml` all meine Optionen die ich haben will (zum Beispiel die Volumes oder Ports) und mit `docker-compose up` wird alles hochgefahren. Ich muss mir mein ursprüngliches `docker run`-Kommando nicht merken. Am schönsten wird es wenn wir mehrere Container miteinander verkleben. Bei Owncloud hantieren wir mit nur einem Container. Das File sieht dann so aus:
|
||
|
|
||
|
```
|
||
|
owncloud:
|
||
|
build: .
|
||
|
ports:
|
||
|
- "127.0.0.1:9998:80"
|
||
|
volumes:
|
||
|
- "/srv/www/owncloud/config:/var/www/owncloud/config"
|
||
|
- "/srv/www/owncloud/data:/var/www/owncloud/data"
|
||
|
```
|
||
|
|
||
|
Wie man sieht steht nicht wirklich viel drin aber es erleichtert das starten und bauen sehr.
|
||
|
|
||
|
## tiny tiny rss
|
||
|
|
||
|
[tiny tiny rss](https://tt-rss.org) war dann meine Master-Arbeit. Hier gab es dann gleich mehrere Problemszenarien die zu bewältigen waren. Ich finge also an ein einfaches Dockerfile zusammen zu hacken. Es gab dann aber ein paar Probleme. Zum Beispiel muss die Datenbank bestehen bleiben auch wenn ich den Container lösche. Das einrichten der Datenbank erfolgt aber durch einen Setup Screen von tt-rss bei ersten aufrufen. Das gleiche gilt für das Configfile. Im Dockerfile kann man nicht andere Volumes von anderen Container definieren die zum speichern von Daten genutzt werden (dies ist ein Weg bestimmte Daten vor dem löschen zu bewahren). Also war mir klar das ich ein Script haben muss welches bei jedem erstellen des Containers sicherstellt das das tt-rss Datenbankschema in der Datenbank sich befindet und die richtige Config an der richtigen Stelle liegt. Da kommt ein Liebling von mir ins Spiel: [Ansible](http://ansible.com/). Ich definiere einen `ENTRYPOINT`. Ein einfaches Bash-Script welches Ansible aufruft und danach Supervisor um alles zu starten. Mein Ansible-Playbook sieht so aus:
|
||
|
|
||
|
```
|
||
|
---
|
||
|
- hosts: localhost
|
||
|
remote_user: root
|
||
|
|
||
|
tasks:
|
||
|
|
||
|
- name: create ttrss config.php
|
||
|
template: src=templates/config.php.j2
|
||
|
dest=/var/www/tt-rss/config.php
|
||
|
|
||
|
- name: pause everything
|
||
|
pause: seconds=30
|
||
|
|
||
|
- name: ttrss db
|
||
|
mysql_db: name=ttrss
|
||
|
state=present
|
||
|
login_host={{ lookup('env','DB_PORT_3306_TCP_ADDR') }}
|
||
|
login_user=root
|
||
|
login_password={{ lookup('env','DB_ENV_MYSQL_ROOT_PASSWORD') }}
|
||
|
notify: import ttrss schema
|
||
|
|
||
|
handlers:
|
||
|
|
||
|
- name: import ttrss schema
|
||
|
mysql_db: name=ttrss
|
||
|
state=import
|
||
|
target=/var/www/tt-rss/schema/ttrss_schema_mysql.sql
|
||
|
login_host={{ lookup('env','DB_PORT_3306_TCP_ADDR') }}
|
||
|
login_user=root
|
||
|
login_password={{ lookup('env','DB_ENV_MYSQL_ROOT_PASSWORD') }}
|
||
|
```
|
||
|
|
||
|
Ich erstelle die Config aus einem Template. Dann kommt der "hacky" Teil. Ich muss 30 Sekunden warten. Dies beruht darauf das `docker-compose` alle Container parallel startet und dadruch bekomme ich Connection Probleme bei einrichten der Datenbank weil diese einfach noch nicht hochgefahren ist. Nicht schön... läuft aber. Dann gehen wir sicher das es eine DB mit dem Namen "ttrss" gibt. Wenn nicht wird der Handler `import ttrss schema` angestoßen der dann das Schema importiert. Die Supervisor-Config sieht so aus:
|
||
|
|
||
|
```
|
||
|
[supervisord]
|
||
|
nodaemon = true
|
||
|
|
||
|
[program:nginx]
|
||
|
command = nginx
|
||
|
user = root
|
||
|
autostart = true
|
||
|
|
||
|
[program:php]
|
||
|
command = php5-fpm --nodaemonize
|
||
|
user = root
|
||
|
autostart = true
|
||
|
|
||
|
[program:ttrss-update-daemon]
|
||
|
command = php /var/www/tt-rss/update_daemon2.php
|
||
|
user = www-data
|
||
|
autostart=true
|
||
|
```
|
||
|
|
||
|
Was dazu kam ist der `ttrss-update-daemon`. Er wird gestartet um die Feeds, im Hintergrund, zu aktualisieren. Die `docker-compose.yml` sieht wie folgt aus:
|
||
|
|
||
|
```
|
||
|
ttrss:
|
||
|
build: .
|
||
|
ports:
|
||
|
- "127.0.0.1:9997:80"
|
||
|
environment:
|
||
|
- URL_PATH=https://reader.domain.foo
|
||
|
links:
|
||
|
- db
|
||
|
db:
|
||
|
image: mariadb
|
||
|
volumes_from:
|
||
|
- ttrss-data
|
||
|
environment:
|
||
|
- MYSQL_ROOT_PASSWORD=mysecretpassword
|
||
|
|
||
|
```
|
||
|
|
||
|
Hier sieht mand ie ganze docker-compose Magic. Wir definieren alle Container die gebraucht werden und vor allem wie sie verlinkt werden sollen. Dann können wir auch gleich noch ein paar Variabeln mitgeben. `URL_PATH` wird für die tt-rss Config gebraucht und `MYSQL_ROOT_PASSWORD` um MariaDB zu initialisieren. Wir benutzen einen [Data-Only-Container](https://docs.docker.com/userguide/dockervolumes/) um die Datenbank zu speichern. Diesen legen wir mit `docker run --name ttrss-data mariadb true` an. Wir benutzen hier das `mariadb`-Image damit die Permissions mit dem Server übereinstimmen. `docker-compose up` und den Reverse Proxy setzen. Zack fertig! [Hier](https://github.com/xsteadfastx/ttrss_docker) gibt es alle benötigten Files.
|
||
|
|
||
|
## Plex Media Server
|
||
|
|
||
|
Ich liebe Plex ja. Auch wenn es teilweise closed-source ist komme ich einfach nicht davon weg. Von der Usability habe ich bis jetzt nicht vergleichbares gefunden. Also was liegt näher als Plex auch im Container laufen zu lassen. Komischerweise war Plex die einfachste Aufgabe bis jetzt. Alles ziemlich straight-forward. Deswegen einfach [hier](https://github.com/xsteadfastx/plex_docker) alle Files. Bis jetzt rennt Plex. Na mal schauen :)
|
||
|
|
||
|
## Links
|
||
|
|
||
|
Hier sind die Links zu meinen Dockerfiles und den dazugehörigen Helper.
|
||
|
|
||
|
* [owncloud_docker](https://github.com/xsteadfastx/owncloud_docker)
|
||
|
* [ttrss_docker](https://github.com/xsteadfastx/ttrss_docker)
|
||
|
* [plex_docker](https://github.com/xsteadfastx/plex_docker)
|