OSS ライセンスのみでDocker/Kubernetes環境を構築してみた


本稿はJCB Advent Calendar 2022の12/8の記事です。

JCB デジタルソリューション開発部 の四方と申します。 本記事では、OSS ライセンスのみでDocker/Kubernets 環境を構築した取り組みについてご紹介します。

やりたいこと

以下を満たすことを目標としました。

  • Dockerおよび簡易的なKubernetes クラスタが構築可能であること
  • Intel/Apple silicon のどちらでも動作可能であること
  • インターネット上で検索し、情報が豊富な製品であること

上記の要件を満たすツールとして、Multipass, Lima が候補にあがりました。

はじめにMultipass の導入を試みましたが、私の開発環境では相性が悪く利用を断念することになり、Lima の導入を進めることとなりました。

Lima 概要

Limaは公式リポジトリに記載の通り、Linux の仮想環境を構築します。 機能としてファイル共有、ポートフォワード、containerd(他のコンテナランタイムも利用可)を備えています。

Lima 導入

Lima のGitHub リポジトリを参照し、実際に環境を構築していきます。

コマンドをインストール

Homebrew が利用可能です。

brew install lima

インスタンスの構築

以下のコマンドで環境を構築できます。

limactl start <template://TEMPLATE>

既存のテンプレートが複数提供されており、用途に応じて選択できます。 今回は、docker を使用できることが要件となるためdocker のテンプレートを使用しました。

テンプレートはyaml ファイルでも配布されているので、修正したyaml を利用する場合は以下のコマンドで実行します。 *1https://github.com/lima-vm/lima/blob/master/examples/docker.yaml

limactl start /path/to/docker.yaml

Lima テンプレート修正

デフォルトのテンプレートのままでは弊社の環境では動作しなかったため、テンプレートを修正しました。

中間証明書の設定

proxy の環境等を構築している場合、証明書の設定をする必要があります。

caCerts:
  # If set to `true`, this will remove all the default trusted CA certificates that
  # are normally shipped with the OS.
  # 🟢 Builtin default: false
  removeDefaults: null

  # A list of trusted CA certificate files.
  # The files will be read and passed to cloud-init.
  files:
  # - examples/hello.crt

  # A list of trusted CA certificates. These are directly passed to cloud-init.
  certs:
  # - |
  #   -----BEGIN CERTIFICATE-----
  #   YOUR-ORGS-TRUSTED-CA-CERT-HERE
  #   -----END CERTIFICATE-----
  # - |
  #   -----BEGIN CERTIFICATE-----
  #   YOUR-ORGS-TRUSTED-CA-CERT-HERE
  #   -----END CERTIFICATE-----

この記述を追記することでproxy 環境下でもLima で構築したvm が外部サイトと通信可能になります。

カーネルパラメータの調整

Docker 利用時に下記のメッセージが出るため、こちらもテンプレートを修正し対応しました。

# 下記メッセージが出たため、yaml にカーネルパラメータの調整を追記
max virtual memory areas vm.max_map_count [65530] is too low
provision:
  - mode: system
    script: |
      #!/bin/bash
      # kernel parameter tuning
      set -eux -o pipefail
      sysctl -w vm.max_map_count=262144
      sysctl -p

Docker 動作確認

これまでの設定をしていれば、limactl start コマンドでインスタンスが正常に起動します。 実際にmacOS 上からdocker コマンドを叩いてみて動作を確認します。

$ limactl start docker
INFO[0000] Using the existing instance "docker"
INFO[0001] SSH Local Port: 49591
INFO[0001] [hostagent] Waiting for the essential requirement 1 of 5: "ssh"
INFO[0021] [hostagent] The essential requirement 1 of 5 is satisfied
: 中略

INFO[0058] READY. Run `limactl shell docker` to open the shell.
INFO[0058] Message from the instance "docker":
To run `docker` on the host (assumes docker-cli is installed), run the following:
------
docker context create lima-docker --docker "host=***"
docker context use lima-docker
docker run hello-world
------

# docker コマンドの動作確認
$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:faa03e786c97f07ef34423fccceeec2398ec8a5759259f94d99078f264e9d7af
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

問題なくdocker を使用できていることが確認できました。

minikube 構築

ここまででDocker が利用できるようになりましたので、続いてKubernetes クラスタを構築します。 クラスタ構築にはminikube を利用しました。

macOS 上でminikube コマンドを用いる場合、MacBook のCPUアーキテクチャとLimaインスタンスのCPUアーキテクチャが一致している必要があります。

今回はアーキテクチャをあえて一致させないユースケースを考慮して対策を講じました。 そこでminikube コマンドの実行をmacOS 上ではなく、Lima インスタンス側に変更しました。

テンプレートを修正し、Lima インスタンスのCPU アーキテクチャに応じたminikube の導入を自動化しました。

- mode: user
  script: |
    #!/bin/bash
    # minikube install
    BASEURL=https://storage.googleapis.com/minikube/releases/latest
    ARCH=$(arch)
    mkdir -p ~/tmp
    case "$ARCH" in
      "x86_64" | "i386" )
        curl -Lo ~/tmp/minikube $BASEURL/minikube-linux-amd64;;
      "aarch64" )
        curl -Lo ~/tmp/minikube $BASEURL/minikube-linux-arm64;;
      * )
        echo "default";;
    esac
    install ~/tmp/minikube ~/bin/minikube

上記のように記載することで、インスタンスを構築するユーザがCPUのアーキテクチャを意識しなくてもminikube コマンドが利用できるようになりました。

中間証明書の設定 with minikube

Lima インスタンス同様、minikube にも証明書の設定をする必要があります。 以下の証明書の設定をテンプレートに追記しました。

- mode: user
  script: |
    #!/bin/bash
    # certs ディレクトリがなければ作成
    mkdir -p ~/.minikube/certs
    cat <<EOF> ~/.minikube/certs/nscert.pem
    -----BEGIN CERTIFICATE-----
    # 証明書
    -----END CERTIFICATE-----
    EOF

ホームディレクトリ配下に.minikube/certsディレクトリを作成し、証明書を配置しました。 minikube の起動コマンドに--embed-certs を追加することで証明書をminikube が認識してくれるようになります。

minikube 構築の自動化

カスタムしたテンプレートを使用するメンバーに、極力コマンドを実行させなくても良いようにminikube の起動は自動化させることにしました。 以下の設定をテンプレートに追記しました。

- mode: user
  script: |
    #!/bin/bash
    # minikube の起動を自動化するためsystemd unit を作成
    cat <<EOF> ~/.config/systemd/user/minikube.service
    [Unit]
    Description=minikube
    Requires=docker.service
    After=docker.service

    [Service]
    Type=oneshot
    RemainAfterExit=yes
    WorkingDirectory=~
    ExecStart=/usr/local/bin/minikube start --wait-timeout=15m0s --embed-certs
    ExecStop=/usr/local/bin/minikube stop
    Restart=on-failure

    [Install]
    WantedBy=default.target
    EOF
    systemctl --user enable minikube.service
    systemctl --user start minikube.service

minikube をsystemd 管理で起動させることによって、Lima インスタンス起動時に自動でKubernetes クラスタが構築されるようになりました。

動作確認

ここまでの設定を反映したdocker.yaml を使用して、Lima インスタンスを起動しKubernetes クラスタ上にpod を動かしてみます。

$ limactl list
NAME      STATUS     SSH                ARCH      CPUS    MEMORY    DISK     DIR
docker    Running    127.0.0.1:49591    x86_64    4       8GiB      64GiB    /Users/shikata/.lima/docker

$ alias lsd='limactl shell docker'
$ alias lsdmk='limactl shell docker minikube kubectl --'
# minikube の動作状況を確認
$ lsd minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

# 試しにnginx のpod を起動
$ lsdmk run nginx --image=nginx
pod/nginx created

$ lsdmk get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          9s

# コンテナ内に入り、curl でレスポンスが帰ることを確認
$ lsdmk exec -it nginx -- bash
root@nginx:/# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@nginx:/# exit
exit

問題なくKubernetes クラスタとして動作していることが確認できました。

まとめ

OSS ライセンスのみでDocker/Kubernetes 構築を実施いたしました。 テンプレートを修正するだけで対応が可能なLima の柔軟性を感じることが出来ました。

最後になりますが、JCBでは我々と一緒に働きたいという人材を募集しています。 詳しい募集要項等については採用ページをご覧下さい。


本文および図表中では、「™」、「®」を明記しておりません。 Google Cloud, GCPならびにすべてのGoogleの商標およびロゴはGoogle LLCの商標または登録商標です。 記載されているロゴ、システム名、製品名は各社及び商標権者の登録商標あるいは商標です。

*1:テンプレート

©JCB Co., Ltd. 20︎21