VPS dla początkujących cz. 6: przydatne dodatki, poprawki i aktualizacje

Napisano dnia 16.06.2022 r. o godzinie 20:46
Autor: Piotr Sperka

Wstęp

Cześć, witaj po długiej przerwie! VPS, który powstał na podstawie poprzednich odcinków działa już prawie rok. Przez ten czas poprawiałem drobne niedogodności w jego funkcjonowaniu, a także kilkukrotnie zaktualizowałem zarówno pakiety systemu, jak i wersje kontenerów działające na Dockerze. W dzisiejszym odcinku przestawię po kolei rozwiązanie napotkanych przeze mnie problemow oraz jak aktualizować kontenery.

Automatyczne odnawianie certyfikatów i restart po ich odnowieniu

Certbot, którego użyłem do pobrania certyfikatów LetsEncrypt powinien automatycznie je odnawiać przed upływem ich ważności. Stało się tak raz, drugi, ale w pewnym momencie, po którejś aktualizacji systemu Certbot odmówił dalszej współpracy. Krótka analiza pokazała, że uruchamiany przez CRONa skrypt sprawdza, czy w systemie jest usługa timer systemd. Jeśli jest, zaprzestaje działania. Problem w tym, że w moim przypadku żaden timer nie był stworzony. Szybkim rozwiązaniem tego problemu była modyfikacja pliku /etc/cron.d/certbot do następującej postaci:

0 */12 * * * root perl -e 'sleep int(rand(43200))' && certbot -q renew

Odświeżanie certyfikatu zaczęło działać ponownie. W ten sposób pominąłem sprawdzanie istnienia usługi timerów i zdałem się na działanie CRONa. Z pewnością nie jest to rozwiązanie idealne i eleganckie, jednak w tamtym momencie nie miałem czasu na więcej. Mogę za to zapewnić, że odśweżanie certyfikatów działa od tamtej pory bezbłędnie.

Przejdę teraz płynnie do restartu kontenerów Dockerowych wykorzystujących certyfikaty. Restart ten jest oczywiście konieczny po tym, jak Certbot pobierze nowe certyfikaty. Analizując wyniki komendy ls /etc/cron.*/* widać, że jest tam wpis /etc/cron.d/certbot. Rzeczywiście, Certbot cyklicznie odpala się, widać to nawet w logu (grep CRON /var/log/syslog). Pokazuje to, że Certbot pobierze nowe certyfikaty, gdy obecne będą bliskie wygaśnięcia, jednak restart chcę wykonać tylko, gdy rzeczywiście nowe certyfikaty się pojawią, a nie za każdym wywołaniem Certbota przez CRON. Nada się do tego post deploy hook. Stworzyłem plik /docker/cert-post-deploy-hook.sh o następującej treści:

#!/bin/bash
cd /docker/mailu
cp /etc/letsencrypt/live/sperka.pl/fullchain.pem /docker/mailu/certs/cert.pem
cp /etc/letsencrypt/live/sperka.pl/privkey.pem /docker/mailu/certs/key.pem
/bin/docker-compose restart
cd /docker/nginx-proxy
/bin/docker-compose restart

Skrypt ten kopiuje certyfikaty do odpowiedniego katalogu dla Mailu, restartuje usługę, a także restartuje reverse proxy oparte na Nginxie. Trzeba jeszcze nadać skrytpowi odpowiednie uprawnienia komendą:

chmod 700 /docker/cert-post-deploy-hook.sh

Następnie wyedytowałem plik /etc/letsencrypt/cli.ini i dopisałem linię

deploy-hook = /docker/cert-post-deploy-hook.sh

Skrypt powinien wykonać się po odnowieniu certyfikatów, i po kilku kolejnych odświeżeniach mogę potwierdzić, że uruchamia się.

Zmiana strefy czasowej

Przy okazji analizy logów podczas poprawiania problemu z odświeżaniem certyfikatów zauważyłem, że nie zgadza się godzina. W związku z tym sprawdziłem komendę timedatectl. Oto co wykazała:

root@sperka:/var/log# timedatectl
Local time: Tue 2021-09-21 10:02:12 EDT
Universal time: Tue 2021-09-21 14:02:12 UTC
RTC time: Tue 2021-09-21 14:02:13
Time zone: America/New_York (EDT, -0400)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

W związku z tym wykonałem polecenie timedatectl set-timezone Europe/Warsaw i ponownie sprawdziłem czas:

root@sperka:/var/log# timedatectl
Local time: Tue 2021-09-21 16:03:13 CEST
Universal time: Tue 2021-09-21 14:03:13 UTC
RTC time: Tue 2021-09-21 14:03:14
Time zone: Europe/Warsaw (CEST, +0200)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

Jak widać, tym razem strefa czasowa była już poprawna.

Aktualizacja Nextcloud

Na początek wątku na temat aktualizacji zajmę się aktualizacją Nextcloud. Ma to swoje uzasadnienie. Okazuje się, że czasami aktualizacja tej usługi nie jest taka prosta jak być powinna. Do tematu aktualizacji Nextcloud przystąpiłem po tym, jak zauważyłem problem z jego obsługą poprzez aplikację Pliki na iOS. Aplikacja pobiera wszystkie pliki z danego katalogu zaraz po wejściu do niego, a nie po wejściu w plik. Jest to okropnie irytujące i niepotrzebnie zużywa przestrzeń na urządzeniu. Po dłuższych poszukiwaniach w czeluściach Internetu nie znalazłem żadnych konkretów, poza kilkoma opisami podobnych problemów – niestety, bez rozwiązania. Z braku lepszych pomysłów postanowiłem zaktualizować aplikację na serwerze.

Mogłoby się wydawać, że aktualizacja to nic trudnego. Jednak w przypadku Nextcloud (a zapewne także i innych bardziej złożonych usług) należy pamiętać, żeby nie próbować za jednym strzałem podbić wersji o więcej niż jedno główne wydanie. Na przykład próba podbicia wersji z 21 na 23 skończy się błędem i sporymi problemami. Dlatego na początek apeluję – zrób backup bazy i plików Nextcloud przed przystąpieniem do akcji!

Tym razem robiłem aktualizację z wersji 21.0.3 do aktualnej z tagu production, czyli 22.2.3. Na początek wykonałem docker-compose down, zrobiłem kopię zapasową i wyedytowałem plik docker-compose.yml. Jeśli korzystasz z konfiguracji z tej serii poradników, musisz najpierw rozwinąć nieco parametr command w konfiguracji bazy danych MariaDB. Poniżej przedstawiłem aktualny fragment:

  nextcloud-db:
    image: mariadb:latest
    restart: always
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW --innodb-file-per-table=1 --skip-innodb-read-only-compressed
    volumes:
      - /docker/nextcloud/mysql:/var/lib/mysql
    environment:
      - MYSQL_RANDOM_ROOT_PASSWORD='1'
      - MYSQL_PASSWORD=supertajnehaslo
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
    networks:
      - reverse_proxy

Pozwoli Ci to z góry uniknąć nieudanej migracji bazy danych zakończonej błędem: Nextcloud 4047 InnoDB refuses to write tables with ROW_FORMAT=COMPRESSED or KEY_BLOCK_SIZE. Dodatkowo zmodyfikowałem też nazwę tagu obrazu Nextcloud z latest na production. Jest to istotne – gdybym nie zmienił tagu i wykonał aktualizację obrazu, utknąłbym na etapie migracji bazy danych, ponieważ podbiłbym wersję z 21 do 23. Który tag odpowiada której wersji można sprawdzić w opisie kontenera na Docker Hubie.

Po modyfikacji pliku docker-compose.yml wykonałem polecenia docker-compose pull a następnie docker-compose up -d. Po uruchomieniu kontenerów wykonałem zgodnie z dokumentacją na Docker Hubie polecenie:

docker exec --user www-data CONTAINER_ID php occ upgrade

Na koniec zrestartowałem reverse proxy i Nextcloud zaczął być ponownie dostępny, już w nowej wersji. Kilka miesięcy później ponownie podbijałem wersję Nextclouda, i tym razem jedyne co musiałem wykonać do polecenia:

docker-compose pull
docker-compose up -d

oraz zrestartować reverse proxy.

Aktualizacja pozostałych kontenerów

Po nieco złożonej aktualizacji Nextcloud przejdę płynnie do aktualizacji pozostałych kontenerów. Jest to prosta sprawa i polega na wykonaniu poleceń w każdym z katalogów z docker-compose:

docker-compose pull
docker-compose up -d

Na koniec warto zrestartować reverse proxy poleceniami (wykonanymi w katalogu reverse proxy):

docker-compose down
docker-compose up -d

Kolejność startu kontenerów

Od początku borykałem się z problemem automatycznego startu kontenerów. Problem był, dokładniej rzecz biorąc taki, że kontenery startowały w nieodpowiedniej kolejności. W efekcie przynajmniej jeden z nich nie wstawał poprawnie, co skutkowało błędem startu reverse proxy. Przez to żadna usługa nie była dostępna aż do momentu ręcznego uruchomienia brakującego kontenera i restartu reverse proxy. Było to szczególnie drażniące w przypadku usług mailowych, ponieważ po odnowieniu certyfikatu lub restarcie Dockera (na przykład po aktualizacji) mail przestawał działać.

W moim przypadku kłopoty sprawiała usługa apache-lamp, której nie opisywałem w tej serii poradników. Jest to kontener zawierający serwer Apache wraz z PHP oraz bazą MariaDB. Jednakże, jeśli chodzi o wszystkie pozostałe usługi, należy zadbać, żeby w plikach docker-compose.yml miały ustawiony parametr restart: always. Zapewni to, że w przypadku błędu podczas startu, usługa zrestartuje się. Dzięki temu wszystkie usługi powinny wstać automatycznie po starcie Dockera, nawet, jeśli zajmie im to kilka restartów.

Aktualizacja systemu

Wydaje mi się, że jest to oczywista sprawa, ale dla spokoju sumienia o tym wspomnę. Każdy system, w szczególności serwerowy warto regularnie aktualizować, żeby zapewnić wszystkie najnowsze poprawki bezpieczeństwa. W tym celu z konta roota w systemie należy wywołać polecenia:

apt update
apt upgrade

Czyszczenie pozostałości po aktualizacjach i usuniętych kontenerach

Warto co jakiś czas (na przykład po aktualizacji kontenerów) uruchomić polecenia, które kolejno pozwalają usunąć nieużywane już obrazy dockerowe, oraz usunąć pozostałości po usuniętych kontenerach (na przykład nieużywane sieci). Są to polecenia:

docker system prune
docker image prune -af

Podsumowanie

Ten odcinek może wydawać się nieco chaotyczny i nie dotyczący niczego konkretnego, jednak z założenia miał być rodzajem zbioru wniosków i note to self. Zdaję sobie sprawę, że ta część nie ukazała się w czasie, w jakim powinna była się ukazać (czyli tak z 8 miesięcy temu…). Cóż mogę napisać – praca i nawał obowiązków. Mam jedynie nadzieję, że kolejne artykuły ukażą się z nieco mniejszymi opóźnieniami. Tym samym powoli dobiegliśmy do końca serii „VPS dla początkujących”. Nie wykluczam, że jeszcze pojawi się jakiś dodatkowy odcinek, jeśli będę miał coś ciekawego do pokazania. Mam nadzieje, że zawarte tu porady okazały się pomocne. Do następnego 😉