🌟

おうちでGitOps (GitLab + Kubernetes + Flux) - シリーズ投稿1/6

2023/06/28に公開

以前、おうちのラボでDockerを使ってサービスを
いろいろ走らせてみようという記事をシリーズで書きましたが、
今度はGitOps環境をおうちのラボに用意して遊ぼうという記事を書きます。
GitLab + Kubernetes + Fluxといった組み合わせです。

Previous Series on Docker: Dockerで作るおうちLAN遊び場 シリーズ1/7

出来上がるもの

今回のシリーズで最初に紹介したいのは次の3つです。

  • Kubernetesクラスタ
  • Kubernetesクラスタを操るGitレポジトリ
  • そのGitレポジトリを読み取りKubernetesクラスタに変更を加えるGitOpsツールであるFlux

Kubernetes用の設定ファイルをGitレポジトリに上げると、そのファイル通りにFluxがKubernetesクラスタを更新します。つまり動かしたいものを書いてGitレポジトリにプッシュすると、あとは自動でそれがKubernetes上に実装されるようになります。

例えばJupyter Notebookを動かすmanifestファイルを書いてGitレポジトリにpushすれば、Jupyter NotebookがKubernetesクラスタ上に自動的に作られるようになります。

更にこのシリーズでは、走らせるサービスへのアクセスもDNSサーバやウェブサーバへの変更を通じて出来るようにする工夫も紹介します。簡単に言えば、Kubernetesクラスタ上で、クラスタ外からアクセスできるようになっているサービスの確認、そしてその名前やIPアドレスをDNSやリバースプロキシが処理できるよう設定を投げ込むといったことをするスクリプトを用意します。

ここまでできれば、マニフェストを書く、すると自動でKubernetesクラスタ上でサービスが立ち上がる、更にブラウザでアクセスする準備も勝手に整うということになります。

ToC

このシリーズの目次は次のとおりです。

  • おうちでGitOps シリーズイントロ (本ポストでカバー)
    • 最終的に何ができるのかの紹介
  • GitLab + Nginx + Unbound DNS用意 (本ポストでカバー)
    • 私はすでにこれらが揃っている環境でk8sクラスタ構築へと進んだのでまずはそこまで...
  • Kubernetesクラスタ構築 (実際のクラスタ構築は次のポストで!)
    • ラズパイやファンレスミニPCでの必要な事前設定あれこれ
    • k8s v1.27.1 + containerd as CRI + flannel as network plugin
  • Flux導入とMetalLB実装
    • GitLabにGitOps用レポジトリ用意
    • Fluxで対象レポジトリへbootstrap
    • MetalLBのmanifestをレポジトリに配置してKubernetesクラスタへ実装
  • Weave GitOps Dashboard導入
    • 手動でDNSやRPを設定するという手間を経てLAN上の他の端末からもアクセスできるように
  • おうちラボでKubernetesサービスへのウェブアクセス自動実装
    • 前のポストで触れた手間を自動化
  • Kubernetesでのcsi-driver-nfsを用いたNFS利用

本シリーズのお約束

  • Kubernetes Cluster on 3 nodes (2 raspberry pi4 - arm64, and 1 amd64 fanless mini PC)
    • flannel for networking
    • flux as a GitOps tool
    • metallb for LoadBalancer service type implementation
  • 1 or more machine running Docker
    • serving GitLab (Used for GitOps central repository)
    • serving Nginx (Reverse proxy to provide access to GitLab and other web services to be created on Kubernetes Cluster)
    • serving Unbound (DNS resolver for machines on LAN)
  • public DNS domain + SSL/TLS certification (for example, Let's Encrypt) recommended
    • they are all mydomain.net in the series
    • replace mydomain.net with your own DNS domain to follow through

More on Docker - Series Top: Dockerで作るおうちLAN遊び場 シリーズ1/7

Interested in getting your own DNS domain?

GitLab, Nginx, and Unbound on Docker

まず私のおうちラボ環境には元々DockerコンテナとしてGitLab、Nginx、Unboundが稼働しています。Kubernetesクラスタを作って遊ぼうと思ったとき、設定はgitレポジトリに載せておきたい、Kubernetesクラスタ上で稼働させるサービスはUnboundとNginxを利用してアクセスできるようにしたいと考えていました。そういうわけで全てを繋げて先のような目次になったのですが、このポストの残りでこれら既存サービスのセットアップについて触れておきます。

基本的に別シリーズで紹介した通りのセットアップであり、一番異なる部分はパブリックで通用するドメインおよびlet's encrypt証明書を使用しているところです。

ドメインはシリーズ通してmydomain.netとしていきますが、ご自身でドメインと*.mydomain.netのようなワイルドカード証明書を用意すればスムーズに進められると思います。

Unbound

まずDNSサービスですが、docker-compose.ymlと、DNSレコードを載せるファイルconfig/a-records.confを用意し、docker compose up -dで走らせるだけとなります。

❯ tree
.
 |-config
 | |-a-records.conf
 |-docker-compose.yml


# ❯ which tree
# tree: aliased to find . -not -path "*/\.git/*" -not -path "*/venv/*" | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/"

docker-compose.yml

まずはdocker-compose.ymlです。イメージはmvance/unboundを利用させて頂きます。Docker hubでタグ・バージョンを確認して好きなものを利用しましょう。

version: '3'
services:
  unbound:
    image: mvance/unbound:1.16.2
    restart: unless-stopped
    container_name: landns
    hostname: 'landns'
    ports:
      - '53:53/udp'
      - '53:53'
    volumes:
      - './config/a-records.conf:/opt/unbound/etc/unbound/a-records.conf:ro'

unbound config files

Unbound用の設定ファイルですが、a-records.confには好きなレコードを書いておけばこのコンテナがその通りに名前解決してくれます。ここではgitlab.mydomain.net.を追加していますが、IPアドレスはNginx、リバースプロキシサーバのコンテナを走らせるノードのIPアドレスとしておきましょう。

例えば192.168.1.55のノードでUnboundとNginxを走らせ、192.168.1.56でGitLabを走らせる場合、gitlab.mydomain.net.というGitLabへのアクセスリクエストはまずリバースプロキシに到達してほしいので以下のようになります。

local-data: "gitlab.mydomain.net. IN A 192.168.1.55"

Nginx

次にNginxです。こちらも私の本当の環境では、別シリーズで紹介した通りAutheliaという2FAサービスを載せたりしてかなりの行数のリストになってしまうのですが、必要最低限をここでは紹介したいと思います。

httpsアクセスを処理するリバースプロキシサーバを用意するのですが、ブラウザでアクセスするときに何も問題が出ないよう、すべてパブリックで通用するドメインおよびTLS証明書でやってほしいです。

ではまずはファイルのリストが次の通りです。

❯ tree
.
 |-docker-compose.yml
 |-conf
 | |-nginx
 | | |-gitlab.conf
 | |-cert
 | | |-fullchain.pem
 | | |-privkey.pem
 | | |-ssl-base.conf
 | | |-ssl-dhparams.pem
 | | |-ssl-wild.conf
 | |-nginx.conf

docker-compose.yml

docker-compose.ymlファイルはこんな感じです。

services:
  nginx:
    image: nginx:1.24.0
    container_name: nginx
    ports:
      - "443:443"
    volumes:
      - ./conf/nginx/:/etc/nginx/conf.d
      - type: bind
        source: ./conf/cert
        target: /etc/nginx/cert
        read_only: true
      - type: bind
        source: ./conf/nginx.conf
        target: /etc/nginx/nginx.conf
        read_only: true

nginx config files

conf/nginx/*.confファイルとしてリバースプロキシ処理させる名前、パス、プロキシとして通信を流す先を設定したファイルを配置し、その時利用するTLS関連の設定や証明書などはconf/certに入れておきます。そしてNginxの基本設定ファイルとしてconf/nginx.confも用意しておきます。

順番に設定ファイルなども紹介していきます。

nginx gitlab.conf

最初はconf/nginx/gitlab.confです。

サーバ名はgitlab.mydomain.netで443ポートで受け付けるようにしてあります。

更にTLS関連の設定としては別ファイルであるconf/cert/ssl-base.confconf/cert/ssl-wild.confを読み込むようにしてあります。

プロキシ先はGitLabサービスを立ち上げるノードのIPアドレスなりDNSなりで指定するのですが、ここでは192.168.1.56としています。

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 443 ssl http2;
    server_name gitlab.mydomain.net;

    # docker resolver
    resolver 127.0.0.11 valid=30s;

    # upload size
    client_max_body_size 10000M;

    # ssl
    include /etc/nginx/cert/ssl-base.conf;
    include /etc/nginx/cert/ssl-wild.conf;

    location / {
        proxy_http_version 1.1;
        set $upstream_gitlab 192.168.1.56:80;
        proxy_pass http://$upstream_gitlab;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

nginx tls files

TLS関連設定を別ファイルとして設けているconf/cert/ssl-base.confconf/cert/ssl-wild.confについてです。

1つ目のssl-base.confではプロトコル、サイファー、使用するDHパラメータキーファイルなどを記載しています。DHパラメータ自体はopenssl dhparam -out ssh-dhparams.pem 4096といったコマンドで生成すればよいかと思います。

# dhparam
ssl_dhparam /etc/nginx/cert/ssl-dhparams.pem;
# options
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

2つ目のssl-wild.confでは単純に使用する証明書とキーを指定しています。ワイルドカードでやっていくつもりなのでいっそ2つのファイルを一つにまとめても良いかもしれません。証明書とキーは自身のドメインのワイルドカード証明書として用意しておきましょう。

# cert/key for *.mydomain.net
ssl_certificate /etc/nginx/cert/fullchain.pem;
ssl_certificate_key /etc/nginx/cert/privkey.pem;

最後にconf/nginx.confという一般設定ファルですが、私は次のようにしています。Elastic Searchで遊んだときの名残で吐き出すログの種類だけ少し足されているデフォルト設定だったかと思います。つまり変更する設定はないということですが、シリーズの後の方で変更を加える予定がありますので、最初からこういう構成で用意しておきましょう。

後々の変更でデフォルト設定だとサーバ名の文字数に関連してエラーを吐いて起動しなくなる可能性が出てきます。server_names_hash_bucket_size設定を追加しておきましょう。

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      '$request_time $upstream_connect_time $upstream_header_time $upstream_response_time $server_name';

    access_log  /var/log/nginx/access.log  main;

    server_names_hash_bucket_size 128;

    sendfile        on;

    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;
}

すべて準備ができたらdocker compose up -dで立ち上げておきましょう。

GitLab

そしてGitLabの準備です。別途設定ファイルと用意する必要がないのでシンプルです。

docker-compose.yml

以下のようなdocker-compose.ymlファイルで、イメージのバージョン・タグ、ホスト名やexternal_urlなどを適当な名前に変えたら、docker compose up -dで立ち上げて完成です。

80番ポートでプレインなhttpでアクセスできるようセットアップし、実際のユーザアクセスはリバースプロキシへのhttps、そしてプロキシとGitLabサーバ間はhttpといったことになります。

services:
  gitlab:
    image: 'gitlab/gitlab-ee:15.10.2-ee.0'
    restart: always
    hostname: 'gitlab.mydomain.net'
    container_name: k8s-gitlab
    privileged: true
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.mydomain.net'
    ports:
      - '80:80'
    volumes:
      - type: volume
        source: v_config
        target: /etc/gitlab
      - type: volume
        source: v_data
        target: /var/opt/gitlab
      - type: volume
        source: v_logs
        target: /var/log/gitlab

volumes:
  v_data: {}
  v_logs: {}
  v_config: {}

完成!!

後はLAN上の普段遣いのスマホなりラップトップなりでDNS設定をDocker上で動かしているUnbound DNSを使うよう設定し、ブラウザでhttps://gitlab.mydomain.netへアクセスできます。

次回 - Kubernetesクラスタのセットアップ

このシリーズの次のポストでは、Raspberry Pi 4やファンレスミニPCでKubernetesクラスタを構築します。

Discussion