freenginxをGitLab CI/CDでビルドしました - 最新バージョン自動ビルド
freenginx
以前の投稿でmercurialのfreenginxレポジトリより1.25.3をビルドしましたが、
今週2024/4/2にfreenginx 1.25.5が来ていたので、今度はそれをもとにGitLab CI/CD + kanikoでビルドしました。
- freenginx:1.25.5
- alpineベース (3.19.1)
- self-managed GitLab (and GitLab Runner for CI/CD)
- kanikoのexecutor:v1.20.1-debugでイメージビルド
- self-managed Harborへビルドイメージ格納、proxy cache利用
20240410追記: もうfreenginx:1.26.0が登場していました。本ポストの最後に最新バージョンのalpineとfreenginxを確認し、ビルドする微改変版を最後に追加しました。
レポジトリの中身
閉じた環境、そしてプライベートのレポジトリでやっておりますので、レポジトリ共有する代わりに中身を紹介します。
freenginxビルド用に設けたレポジトリに用意したファイルは次の通りです。
.
|-.gitlab-ci.yml
|-alpine
| |-Dockerfile
|-docker-entrypoint.sh
|-10-listen-on-ipv6-by-default.sh
|-20-envsubst-on-templates.sh
|-30-tune-worker-processes.sh
|-README.md
|-.git
./docker-entrypoint.sh
などの./*.sh
ファイルはhttps://github.com/nginxinc/docker-nginxより拝借しています。
./alpine/Dockerfile
はalpineイメージをベースにfreenginxをビルドするためのDockerfileです。もしかすると今後./{other dist}/Dockerfile
なども用意するかもしれません。
./.gitlab-ci.yml
はGitLab CI/CDでGitLab Runnerに実行してもらう内容です。
Dockerfile
ベースイメージはproxy越しにpullするようにしています。
freenginxのレポジトリのタグは./.gitlab-ci.yml
より渡しています。
ただ、ベースイメージのタグはハードコードしていますし、
ビルドを回す条件がDockerfile変更時としているため、
freenginxのタグもDockerfile内にハードコードして都度更新でよいかと考えています。
# base alpine image
# https://hub.docker.com/_/alpine
ARG HARBOR_HOST
ARG FREENGINX_TAG
FROM $HARBOR_HOST/cache-dockerhub/library/alpine:3.19.1
# user
RUN addgroup -g 101 -S nginx \
&& adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx
# build deps
RUN apk add --no-cache pcre2-dev tzdata gettext
RUN apk add --no-cache --virtual .build-deps \
gcc \
libc-dev \
make \
openssl-dev \
zlib-dev \
linux-headers \
bash \
alpine-sdk \
findutils \
mercurial
# hg repo
WORKDIR /tmp
RUN hg clone https://freenginx.org/hg/nginx
WORKDIR /tmp/nginx
RUN hg update $FREENGINX_TAG \
&& auto/configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--modules-path=/usr/lib/nginx/modules \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--user=nginx \
--group=nginx \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-http_v3_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' \
&& make \
&& make install
# remove build deps
WORKDIR /
RUN apk del .build-deps && rm -rf /tmp/nginx
# directories and files
RUN mkdir -p /var/cache/nginx/client_temp \
/var/cache/nginx/proxy_temp \
/var/cache/nginx/fastcgi_temp \
/var/cache/nginx/uwsgi_temp \
/var/cache/nginx/scgi_temp \
/docker-entrypoint.d \
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log
COPY docker-entrypoint.sh /docker-entrypoint.sh
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
COPY 20-envsubst-on-templates.sh /docker-entrypoint.d
COPY 30-tune-worker-processes.sh /docker-entrypoint.d
ENTRYPOINT ["/docker-entrypoint.sh"]
EXPOSE 80
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]
.gitlab-ci.yml
kanikoはgcr.io/kaniko-project/executor
にイメージがあるのですが
Dockerfile内、ベースイメージ同様、自前のHarborで設定しているproxyを利用してpullしています。
またGitLabのintegrationsでHarborをセットアップしているので、その変数も用いています。
After the Harbor integration is activated, global variables $HARBOR_USERNAME, $HARBOR_HOST, $HARBOR_OCI, $HARBOR_PASSWORD, $HARBOR_URL and $HARBOR_PROJECT will be created for CI/CD use.
https://docs.gitlab.com/ee/user/project/integrations/harbor.html
./alpine/Dockerfile
に変更があった場合には"build-test"ジョブでビルドするだけ、レポジトリでtagを付けた時はビルドおよびHarborへのプッシュをするようにしています。こういった条件もありますし、先述の通りfreenginxのタグに関してはここから渡すのではなく、Dockerfile内に記載して都度更新するよう変更しようかと考えています。
variables:
KANIKO_CACHE_DIR: "/cache"
FREENGINX_TAG: "release-1.25.5"
stages:
- build
build-test:
stage: build
image:
name: $HARBOR_HOST/cache-gcrio/kaniko-project/executor:v1.20.1-debug
entrypoint: [""]
script:
- echo "{\"auths\":{\"$HARBOR_HOST\":{\"auth\":\"$(echo -n ${HARBOR_USERNAME}:${HARBOR_PASSWORD} | base64)\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor
--build-arg "HARBOR_HOST=$HARBOR_HOST"
--build-arg "FREENGINX_TAG=$FREENGINX_TAG"
--cache
--cache-dir /cache
--cache-copy-layers
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/alpine/Dockerfile"
--no-push
--cache-repo "${HARBOR_HOST}/${HARBOR_PROJECT}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}"
rules:
- changes:
- alpine/Dockerfile
- if: $CI_COMMIT_TAG
when: never
build:
stage: build
image:
name: $HARBOR_HOST/cache-gcrio/kaniko-project/executor:v1.20.1-debug
entrypoint: [""]
script:
- echo "{\"auths\":{\"$HARBOR_HOST\":{\"auth\":\"$(echo -n ${HARBOR_USERNAME}:${HARBOR_PASSWORD} | base64)\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor
--build-arg "HARBOR_HOST=$HARBOR_HOST"
--build-arg "FREENGINX_TAG=$FREENGINX_TAG"
--cache
--cache-dir /cache
--cache-copy-layers
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/alpine/Dockerfile"
--destination "${HARBOR_HOST}/${HARBOR_PROJECT}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:${CI_COMMIT_TAG}"
only:
- tags
retry: 2
イメージ完成
Dockerで動かしているイメージをビルドしたもので差し替えてみると、無事動いてくれました。nginx -V
は以下の通りです。
streamでのtls pass through、tls offloadしての他にDockerで動かしているサービスへのリバースプロキシ、AutheliaにredirectしてのMFAなど、うちの環境で動いているものはすべて問題なさそうでなによりです。
nginx version: freenginx/1.25.5
built by gcc 13.2.1 20231014 (Alpine 13.2.1_git20231014)
built with OpenSSL 3.1.4 24 Oct 2023
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_v3_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'
Harbor上でイメージの脆弱性スキャンをしてくれているTrivyによると該当するものはないようです。2月にDebianのベースイメージでビルドした分では600+のレポートが出てくるので、怖いくらいすっきりしています。
おわりに
先日Harborのメンテナンスをした際に、私が利用させていただいている基本イメージあれこれの脆弱性スキャン結果を見たところ、
alpineは目立って問題が少なかったので他のイメージも試しに作ってみたいと考えていました。
メインのウェブサーバとして利用しているnginx/freenginxも更新したかったのでよい機会でした。
ところでnginxは投稿時点で2月の1.25.4更新が最新でした。今後それぞれの開発がどうなっていくのか気になります。
freenginx - CHANGE
nginx - CHANGE
追記 - 最新バージョン自動ビルドGitLab CI/CD
GitLabのCI/CDはスケジュールに応じて勝手に回すようにもできます。
https://docs.gitlab.com/ee/ci/pipelines/schedules.html
スケジュール機能で定期的に最新のイメージをビルドしてregistryにpushするよう、以下のように./.gitlab-ci.yml
と./alpine/Dockerfile
を改変しました。
.gitlab-ci.yml
- latest-tagというjobで、freenginxのレポジトリより最新タグ取得およびdocker hubよりalpineの最新タグ取得
- build-scheduledというjobでそれらのタグを用いてビルドおよびプッシュ
variables:
KANIKO_CACHE_DIR: "/cache"
stages:
- prepare
- build
latest-tag:
stage: prepare
image: $HARBOR_HOST/cache-dockerhub/library/golang:1.22.2
before_script:
- git --version || apt update && apt install git
- hg --version || apt install mercurial
script:
- git clone https://github.com/pkkudo/taglist && cd taglist && go build
- ./taglist --help
- ALPINE_TAG=$(./taglist -repo alpine)
- echo ALPINE_TAG=$ALPINE_TAG > ${CI_PROJECT_DIR}/.env
- cd ${CI_PROJECT_DIR} && hg clone https://freenginx.org/hg/nginx && cd nginx
- FREENGINX_TAG=$(hg tags --pager false | awk 'NR == 2 {print $1}')
- FREENGINX_VER=$(echo $FREENGINX_TAG | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+')
- echo FREENGINX_TAG=$FREENGINX_TAG >> ${CI_PROJECT_DIR}/.env
- echo FREENGINX_VER=$FREENGINX_VER >> ${CI_PROJECT_DIR}/.env
artifacts:
reports:
dotenv: ${CI_PROJECT_DIR}/.env
### omitting the other build jobs ###
build-scheduled:
stage: build
image:
name: $HARBOR_HOST/cache-gcrio/kaniko-project/executor:v1.20.1-debug
entrypoint: [""]
script:
- echo "{\"auths\":{\"$HARBOR_HOST\":{\"auth\":\"$(echo -n ${HARBOR_USERNAME}:${HARBOR_PASSWORD} | base64)\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor
--build-arg "HARBOR_HOST=$HARBOR_HOST"
--build-arg "FREENGINX_TAG=$FREENGINX_TAG"
--build-arg "ALPINE_TAG=$ALPINE_TAG"
--cache
--cache-dir /cache
--cache-copy-layers
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/alpine/Dockerfile"
--destination "${HARBOR_HOST}/${HARBOR_PROJECT}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:${FREENGINX_VER}"
--destination "${HARBOR_HOST}/${HARBOR_PROJECT}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:latest"
--destination "${HARBOR_HOST}/${HARBOR_PROJECT}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:${FREENGINX_VER}-${ALPINE_TAG}"
retry: 2
needs:
- job: latest-tag
artifacts: true
rules:
- if: $CI_PIPELINE_SOURCE == 'schedule'
Dockerfile
-
ARG ALPINE_TAG
を追加し、FROM
で利用
#syntax=docker/dockerfile:1
# base alpine image
# https://hub.docker.com/_/alpine
ARG HARBOR_HOST
ARG FREENGINX_TAG
ARG ALPINE_TAG
FROM $HARBOR_HOST/cache-dockerhub/library/alpine:$ALPINE_TAG
### no changes in the rest
追記以上です。
Discussion