2022/10/18

Reload Nginx And Apache Config In Docker

如果在本機安裝 apache2 或 nginx 時想要 reload config 的話我們通常會使用下列的指令:

# nginx
nginx -s reload

# apache2
service httpd reload

但在 docker 的環境下就沒有那麼簡單,像 apache 的 reload 是把 script 寫在 service 的 config 裡面,不一定每個 image 裡面都有包含這個指令,CentOS 的我記得好像就沒有,為了要兼容所有的環境,我們可以利用 kill -USR1 這個方式套用到每個我們想要 reload without restart 的專案上面。

apache2

首先在根目錄建立兩個網頁檔:

  • ./www/1/index.html
  • ./www/2/index.html

各別會在網頁印出 1 以及 2 的內容識別。

docker-compose.yml

version: "3.9"

services:
  http:
    ports:
      - "80:80"
    container_name: httpd
    image: httpd
    restart: always
    volumes:
      - "./www:/www"
      - "./config/httpd:/usr/local/apache2/conf:ro"

我們建立了一個名為 http 的 container,使用 httpd 的 image,並且把 www 目錄掛進去,我事先把 httpd 的 config 複製出來以便在外面修改內容,接下來跑 docker compose up -d,打上 IP 後可以看到 httpd 傳統的首頁內容 It works!

接著我們修改 httpd.conf

DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">

# 改為

DocumentRoot "/www/1"
<Directory "/www/1">

我們先使用 docker compose restart 測試,執行後 refresh 網頁可以看到我們要的 1,接著再把 config 改成:

DocumentRoot "/www/2"
<Directory "/www/2">

這次我們使用 docker compose kill -s USR1 http ,此時我們可以看到 container 活得好好的,但 refresh 頁面後得到我們想要的 2 了,他的原理就是呼叫 container 內的 httpd daemon 去重新整理他的 service。

nginx

docker-compose.yml

version: "3.9"

services:
  http:
    ports:
      - "80:80"
    container_name: nginx
    image: nginx
    restart: always
    volumes:
      - "./www:/www"
      - "./config/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf:ro"

一樣,我們事前複製了 nginx 的 config 出來重新掛載回去,啟動 container 以後看見 nginx 的預設字樣 Welcome to nginx!

接著我們修改 defalut.conf

root   /usr/share/nginx/html;

# 改為

root   /www/1;

跟 apache2 一樣我們先使用 docker compose restart,可以順利看到 1 的結果,接著我們將 config 修改為:

root   /www/2;

使用 docker compose exec http nginx -s reload,我們就可以順利看到 2 了,nginx 跟 apache2 的 container 啟動方式不太一樣,所以不能用 kill 的方法,但事實上在 nginx 的 logrotate config 裡面他使用的方式也是:

kill -USR1 `cat /var/run/nginx.pid`

上面介紹了兩個主流網頁伺服器的重取 config 的目的是在當我們把 server 的 log 掛到我們本機目錄時,我們可能會需要依照情況在本機執行 logrotate 的動作,這樣就可以把 reload 腳本寫在本機的 logrotate config 的 postrotate/endscript 裡面了。

這邊附上 logrotate for docker 基本的配置:

nginx-docker

/YOUR_PATH_TO_LOG/*.log {
        daily
        missingok
        rotate 52
        compress
        delaycompress
        notifempty
        create 640 nginx adm
        sharedscripts
        postrotate
            sudo docker exec YOUR_CONTAINER_NAME nginx -s reload
        endscript
}

httpd-docker

/YOUR_PATH_TO_LOG/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        sharedscripts
        postrotate
            sudo docker kill -s USR1 YOUR_CONTAINER_NAME 
        endscript
}

沒有留言: