httpd z PHP w Dockerze

Andrzej Galiński · 2021-03-05

Cel: zainstalować httpd i php w jednym obrazie dockerowym, tak, żeby można było z hosta wyświetlić phpinfo kontenera.

Motywacja

Na codzień nie muszę pisać obrazów Dockerowych (jest tyle gotowych!), ale czasami przydaje się zapakować w jeden kontener coś zbudowanego samodzielnie. Dla uproszczenia w przykładzie nie używam własnych programów, tylko starego dobrego serwera www - z obsługą PHP, żeby było cokolwiek do konfigurowania. Krótkożyjące kontenery “robocze” nie wymagają filozofii - ot, doinstalować zależności, poustawiać zmienne środowiskowe i podmienić konfigurację.

Rozwiązanie

docker-apache/
├── apache-config.conf
├── Dockerfile
├── Makefile
└── www
    └── index.php

Dockerfile:

FROM ubuntu:latest
MAINTAINER Andrzej Galinski <#email#>

ENV DEBIAN_FRONTEND noninteractive

RUN \
    apt-get update && \
    apt-get -y upgrade

RUN \
    apt-get -y install \
        apache2 \
        php7.2 \
        libapache2-mod-php7.2 \
        curl

RUN a2enmod php7.2
RUN a2enmod rewrite

ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ENV APACHE_LOCK_DIR /var/lock/apache2
ENV APACHE_PID_FILE /var/run/apache2.pid

EXPOSE 80

ADD www /var/www/site
ADD apache-config.conf /etc/apache2/sites-enabled/000-default.conf

CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
  • Zaczynam od czystego obrazu Ubuntu
  • Aktualizuję system
  • Doinstalowuję niezbędne pakiety
  • Włączam moduł PHP
  • Ustawiam zmienne httpd (dla porządku, domyślne byłyby OK)
  • Wystawiam na świat port 80
  • Dodaję swoją stronę i podmieniam konfigurację, która ją serwuje
  • Uruchamiam httpd

Konfiguracja httpd:

ServerName foo
<VirtualHost *:80>
    ServerAdmin admin@example.com
    DocumentRoot /var/www/site

    <Directory /var/www/site/>
        Options Indexes FollowSymLinks
        AllowOverride All
        Order deny,allow
        Allow from all
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Strony:

# www/index.php
<?php phpinfo(); ?>

# index2.php - do pokazania podmiany pliku
<?php echo apache_get_version() . "\n"; ?>

Uruchamianie:

build:
	docker build . -t docker_apache_ag
run: build
	docker run -d --rm --name apache_ag -p 8081:80 docker_apache_ag 
	curl http://localhost:8081/index.php | wc
	docker stop apache_ag
run2: build
	docker run -d --rm --name apache_ag -p 8081:80 -v $$PWD/index2.php:/var/www/site/index.php docker_apache_ag 
	curl http://localhost:8081/index.php 
	docker stop apache_ag
  • Buduję obraz z Dockerfile’a w bieżącym folderze i taguję go,
  • uruchamiam kontener,
    • -d - w tle
    • --rm - samokasujący się po zatrzymaniu
    • --name apache_ag - o stałej nazwie (żeby go zatrzymać)
    • -p 8081:80 - z przemapowanym portem hosta (8081) na kontenerowy (80)
  • run: pokazuję, że strona działa,
  • run2: pokazuję, że mogę zamontować plik z macierzystego systemu w kontenerze (podmieniając jego zawartość),
  • …i zatrzymuję kontener.

Uwagi

  • Przy projektowaniu obrazu najlepiej wejść do kontenera (docker run -it <obraz> bash) i tam wykonywać operacje, które następnie utrwali się w Dockerfile’u.
  • Najwięcej czasu zajmuje pierwsza aktualizacja i instalacja pakietów. Późniejsze zmiany w konfiguracji są szybkie, bo Docker przebudowuje tylko “nową” część obrazu.
  • Żeby instalacja pakietów APTem była naprawdę nieinteraktywna, trzeba ustawić flagę DEBIAN_FRONTEND=noninteractive. Można to zrobić w linii z APTem (lokalna zmienna środowiskowa) albo ustawić ją globalnie (ale wtedy pozostanie w env!). Więcej: https://linuxhint.com/debian_frontend_noninteractive/
  • Inne dobre obrazy startowe:
    • alpine:latest (nie ma basha, tylko alias sh; menedżer pakietów to apk)
    • phusion/baseimage (zwł. do kontenerów wieloprocesowych)
    • dowolny obraz, który ma potrzebne narzędzia - najlepiej oficjalny, od autorów (httpd:alpine, node:alpine, …)

Rozmaitości

  • Przy okazji sprawdziłem, dlaczego CentOS jest tak popularny w obrazach dockerowych pod WWW. Bo to open-sourcowa wersja komercyjnego RHEL, który jest bardzo starannie testowany pod kątem stabilności. Do tego gwarantują 10-letnie wsparcie wersji, co jest ewenementem w świecie open-source. Stabilność i przewidywalność biją rozwijanego przez ochotników Debiana.

Linki