オフライン環境にKubernetesを構築する[kubeadm編]

# はじめに
オフライン環境（インターネットにつながらない環境）にKubernetesを構築する手順です。
お勧めしませんが、仕方ないときもあります。
後半で手順の見つけ方も解説します。

# 構築手順について 

## 概要
### 構築フロー
1. インターネットがつながるマシンで必要な物をダウンロード
   * dockerイメージの取得にdockerインストールが必要です
1. 1.でダウンロードしたものをオフライン環境に搬送
2. オフライン環境で構築コマンド実施 

### 構築される構成
* サーバーはIA (IBM PowerやRaspberry Piでない、普通のサーバー)を想定
* OSはUbuntu16.04が構築済みと想定
* Kubernetesバージョンは1.13
* Masterノード一台、他をNodeとする構成
* Dockerバージョンは18.06.1-ce
* CNIプラグインはWeave
* その他はすべてデフォルト

## 手順
### インターネットがつながるマシンで必要な物をダウンロード
1. rootユーザーで次のコマンドを実行してdockerインストール
   
    ```bash:Dockerインストール
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    apt-key fingerprint 0EBFCD88
    add-apt-repository    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) \
    stable"
    apt-get update
    apt-get install -y docker-ce=18.06.1~ce~3-0~ubuntu
    ```
    
1. 必要な物をダウンロード[^1]

```bash:ダウンロードコマンド
# nodeにインストールするdebファイルのダウンロード
wget https://download.docker.com/linux/ubuntu/dists/xenial/pool/stable/amd64/docker-ce_18.06.1~ce~3-0~ubuntu_amd64.deb
wget http://kr.archive.ubuntu.com/ubuntu/pool/main/libt/libtool/libltdl7_2.4.6-0.1_amd64.deb
wget https://packages.cloud.google.com/apt/pool/kubelet_1.13.2-00_amd64_82d092e6177b68cfdde60b9c58de4091ab466e61a4a0328d897275811bc62500.deb
wget http://kr.archive.ubuntu.com/ubuntu/pool/universe/s/socat/socat_1.7.3.1-1_amd64.deb
wget http://kr.archive.ubuntu.com/ubuntu/pool/main/e/ebtables/ebtables_2.0.10.4-3.4ubuntu2.16.04.2_amd64.deb
wget https://packages.cloud.google.com/apt/pool/kubernetes-cni_0.6.0-00_amd64_43460dd3c97073851f84b32f5e8eebdc84fadedb5d5a00d1fc6872f30a4dd42c.deb
wget https://packages.cloud.google.com/apt/pool/kubeadm_1.13.2-00_amd64_1f6de98e354d2b7b8cd6c0c32ae56edd9ca694c64c9a25062d4baee735b78bec.deb
wget https://packages.cloud.google.com/apt/pool/cri-tools_1.12.0-00_amd64_2d9f048a50a9dfeceebd84635f1322955aca6381d9c05b4d60b3da1edb7d856c.deb

# Kubernetesの管理系のdockerイメージダウンロード
sudo docker pull k8s.gcr.io/kube-apiserver:v1.13.2
sudo docker pull k8s.gcr.io/kube-controller-manager:v1.13.2
sudo docker pull k8s.gcr.io/kube-scheduler:v1.13.2
sudo docker pull k8s.gcr.io/kube-proxy:v1.13.2
sudo docker pull k8s.gcr.io/pause:3.1
sudo docker pull k8s.gcr.io/etcd:3.2.24
sudo docker pull k8s.gcr.io/coredns:1.2.6 
sudo docker pull docker.io/weaveworks/weave-npc:2.5.1
sudo docker pull docker.io/weaveworks/weave-kube:2.5.1

sudo docker save k8s.gcr.io/kube-apiserver:v1.13.2 > k8s.gcr.io_kube-apiserver_v1.13.2
sudo docker save k8s.gcr.io/kube-controller-manager:v1.13.2 > k8s.gcr.io_kube-controller-manager_v1.13.2
sudo docker save k8s.gcr.io/kube-scheduler:v1.13.2 > k8s.gcr.io_kube-scheduler_v1.13.2
sudo docker save k8s.gcr.io/kube-proxy:v1.13.2 > k8s.gcr.io_kube-proxy_v1.13.2
sudo docker save k8s.gcr.io/pause:3.1 > k8s.gcr.io_pause_3.1
sudo docker save k8s.gcr.io/etcd:3.2.24 > k8s.gcr.io_etcd_3.2.24
sudo docker save k8s.gcr.io/coredns:1.2.6 > k8s.gcr.io_coredns_1.2.6
sudo docker save docker.io/weaveworks/weave-npc:2.5.1 > docker.io_weaveworks_weave-npc_2.5.1
sudo docker save docker.io/weaveworks/weave-kube:2.5.1 > docker.io_weaveworks_weave-kube_2.5.1

# weaveをCNIプラグインとしてデプロイするyamlのダウンロード
wget -O weave.yml "https://cloud.weave.works/k8s/net?k8s-version=Q2xpZW50IFZlcnNpb246IHZlcnNpb24uSW5mb3tNYWpvcjoiMSIsIE1pbm9yOiIxMyIsIEdpdFZlcnNpb246InYxLjEzLjIiLCBHaXRDb21taXQ6ImNmZjQ2YWI0MWZmMGJiNDRkODU4NDQxM2I1OThhZDgzNjBlYzFkZWYiLCBHaXRUcmVlU3RhdGU6ImNsZWFuIiwgQnVpbGREYXRlOiIyMDE5LTAxLTEwVDIzOjM1OjUxWiIsIEdvVmVyc2lvbjoiZ28xLjExLjQiLCBDb21waWxlcjoiZ2MiLCBQbGF0Zm9ybToibGludXgvYW1kNjQifQpTZXJ2ZXIgVmVyc2lvbjogdmVyc2lvbi5JbmZve01ham9yOiIxIiwgTWlub3I6IjEzIiwgR2l0VmVyc2lvbjoidjEuMTMuMiIsIEdpdENvbW1pdDoiY2ZmNDZhYjQxZmYwYmI0NGQ4NTg0NDEzYjU5OGFkODM2MGVjMWRlZiIsIEdpdFRyZWVTdGF0ZToiY2xlYW4iLCBCdWlsZERhdGU6IjIwMTktMDEtMTBUMjM6Mjg6MTRaIiwgR29WZXJzaW9uOiJnbzEuMTEuNCIsIENvbXBpbGVyOiJnYyIsIFBsYXRmb3JtOiJsaW51eC9hbWQ2NCJ9Cg=="
```

### ダウンロードしたものをオフライン環境に搬送
* 上記コマンドで以下のようにファイルがダウンロードされているはずです。

```bash:ファイル一覧
$ ls
cri-tools_1.12.0-00_amd64_2d9f048a50a9dfeceebd84635f1322955aca6381d9c05b4d60b3da1edb7d856c.deb  k8s.gcr.io_kube-scheduler_v1.13.2
docker-ce_18.06.1~ce~3-0~ubuntu_amd64.deb                                                       k8s.gcr.io_pause_3.1
docker.io_weaveworks_weave-kube_2.5.1                                                           kubeadm_1.13.2-00_amd64_1f6de98e354d2b7b8cd6c0c32ae56edd9ca694c64c9a25062d4baee735b78bec.deb
docker.io_weaveworks_weave-npc_2.5.1                                                            kubectl_1.13.2-00_amd64_fedd83bfb3726db0ad367bc0183fa5d32ecbf30bb806963cd0c027bf2b794b0a.deb
ebtables_2.0.10.4-3.4ubuntu2.16.04.2_amd64.deb                                                  kubelet_1.13.2-00_amd64_82d092e6177b68cfdde60b9c58de4091ab466e61a4a0328d897275811bc62500.deb
k8s.gcr.io_coredns_1.2.6                                                                        kubernetes-cni_0.6.0-00_amd64_43460dd3c97073851f84b32f5e8eebdc84fadedb5d5a00d1fc6872f30a4dd42c.deb
k8s.gcr.io_etcd_3.2.24                                                                          libltdl7_2.4.6-0.1_amd64.deb
k8s.gcr.io_kube-apiserver_v1.13.2                                                               socat_1.7.3.1-1_amd64.deb
k8s.gcr.io_kube-controller-manager_v1.13.2                                                      weave.yml
k8s.gcr.io_kube-proxy_v1.13.2
```

* これらをscpやusb等で搬送してください
* k8sクラスタを構成する全マシンに搬送が必要です[^2]


### オフライン環境で構築コマンド実施 
* 搬送したファイルのあるパスに移動し、全マシンで次のコマンドを実行

```
sudo dpkg -i libltdl7_2.4.6-0.1_amd64.deb
sudo dpkg -i docker-ce_18.06.1~ce~3-0~ubuntu_amd64.deb
sudo dpkg -i ebtables_2.0.10.4-3.4ubuntu2.16.04.2_amd64.deb
sudo dpkg -i socat_1.7.3.1-1_amd64.deb
sudo dpkg -i kubectl_1.13.2-00_amd64_fedd83bfb3726db0ad367bc0183fa5d32ecbf30bb806963cd0c027bf2b794b0a.deb
sudo dpkg -i cri-tools_1.12.0-00_amd64_2d9f048a50a9dfeceebd84635f1322955aca6381d9c05b4d60b3da1edb7d856c.deb
sudo dpkg -i kubernetes-cni_0.6.0-00_amd64_43460dd3c97073851f84b32f5e8eebdc84fadedb5d5a00d1fc6872f30a4dd42c.deb
sudo dpkg -i kubelet_1.13.2-00_amd64_82d092e6177b68cfdde60b9c58de4091ab466e61a4a0328d897275811bc62500.deb
sudo dpkg -i kubeadm_1.13.2-00_amd64_1f6de98e354d2b7b8cd6c0c32ae56edd9ca694c64c9a25062d4baee735b78bec.deb
sudo docker load -i k8s.gcr.io_coredns_1.2.6
sudo docker load -i k8s.gcr.io_etcd_3.2.24
sudo docker load -i k8s.gcr.io_kube-apiserver_v1.13.2
sudo docker load -i k8s.gcr.io_kube-controller-manager_v1.13.2
sudo docker load -i k8s.gcr.io_kube-proxy_v1.13.2
sudo docker load -i k8s.gcr.io_kube-scheduler_v1.13.2
sudo docker load -i k8s.gcr.io_pause_3.1
sudo docker load -i docker.io_weaveworks_weave-kube_2.5.1
sudo docker load -i docker.io_weaveworks_weave-npc_2.5.1
```

* masterで次を実行

    ```bash:kubernetes初期化
    sudo kubeadm init
    ```
* `kubeadm init`の実行結果の末尾に表示される次の形式のコマンドをメモする

    ```bash:メモるコマンド
    kubeadm join <ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<sha>
    ``` 
* 搬送したファイルのあるパスに移動し、masterで次を実行する

    ```bash:kubectlセットアップとWeaveインストール
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config
    kubectl create -f weave.yml"
    ```
* master以外の全ノード上で、メモした`kubeadm join ...`コマンドを実行する
* しばらく待ってからmasterで`kubectl get nodes`を実行し、ノードが`Ready`になればOK

# 手順の見つけ方
* [オンライン前提の手順](https://qiita.com/ozota/items/027befd3fa77a826ea62)をベースに、インターネットに依存する次のコマンドを置き換えます
  * aptインストール
  * Kubernetesシステム用コンテナのダウンロード(docker pull)
  * weaveのデプロイ 

## aptを置き換える
### 必要な知識
* aptはdebファイルのダウンロードと`dpkg -i <debファイル>`によるインストールで置き換えることができます
  * aptでインストールしていたdocker-ce, kubelet, kubeadm, kubectl について、この置き換えが必要です
      * debファイルのダウンロードURLを見つける必要があります。
      * また、dpkgでは依存関係の解決ができないので、その部分を人が行う必要があります
          * 依存するパッケージを見つけ、そのパッケージにもdebファイルのダウンロードと`dpkg -i <debファイル>`実行が必要です
* debファイルのダウンロードURLと依存パッケージを調べるにはPackage一覧をみる必要があります[^3]
  * ubuntu公式パッケージは https://packages.ubuntu.com/ja/ で検索できます 
  * Docker/Kubernetesパッケージについて、Ubuntu16.04(xenial), IAサーバ(amd64)の場合は次で検索できます[^4]
      * dockerのパッケージは https://download.docker.com/linux/ubuntu/dists/xenial/stable/binary-amd64/Packages 
      * Kubernetesのパッケージは https://packages.cloud.google.com/apt/dists/kubernetes-xenial/main/binary-amd64/Packages
 * Package一覧のテキストの中から`Package: <パッケージ名>`で検索してください。
     * `Version: ` にバージョンが記載されています 
          * 見つかったパッケージの`Depends: ..`が依存パッケージです
          * `Filename: `がパッケージのwgetでダウンロードするdebファイルのURLになります。　
              * dockerは https://download.docker.com/linux/ubuntu/ にFilenameをつなげたURLがダウンロードURLです
              * Kubernetesは https://packages.cloud.google.com/apt/ にFilenameをつなげたURLがダウンロードURLです
* パッケージが既にインストールされているかどうかは`dpkg -l <パッケージ名>`と入力して見つかるかで調べることができます
* インストールする際は、依存する順番で`dpkg -i <debファイル>`を実行します

### 手順を見つける手順 
* 上記の知識を元に、次を繰り返すことで依存関係を洗い出しながらdebファイルをダウンロードできます
  * docker-ce, kubelet, kubeadm, kubectl　について、パッケージ一覧を検索
  * ぞれぞれのdebファイルダウンロードURLをメモ
  * それぞれの依存パッケージを再びパッケージ一覧で検索
      * インストールする予定のマシンで`dpkg -l <パッケージ名>`と入力し、見つかる場合はインストール済みなので無視できます
* 洗い出したパッケージの一覧について、debファイルをwgetして搬送後に依存関係順で`dpkg -i`する手順を作ればOKです

## Kubernetesシステム用コンテナのダウンロード
### 必要な知識
* `kubeadm config images list`で必要なイメージのリストが取得できます[^5]
* dockerイメージは`docker save`でファイルに書き出し、`docker load -i <ファイル>`で読み込むことができます

### 手順を見つける手順 
* インターネットにつながる環境でKubeadmをインストールします
* `kubeadm config images list`で必要なイメージのリストを出します
* それぞれについて、`docker pull` & `docker save`でファイルに書き出し、搬送後に`docker load -i <ファイル>`する手順を作ればOKです
 
## weaveデプロイを置き換える
### 必要な知識
* https://cloud.weave.works/k8s/net に適切なクエリパラメーターをつけて http get すると、weaveデプロイ用のKubernetesに投げるyamlを生成してくれます
  * インターネット疎通環境では`kubectl version | base64 | tr -d '\n'`の実行結果をk8s-versionパラメータにつけます
      * `kubectl version | base64 | tr -d '\n'`の結果が必要なため、Kubernetes構築が必要になります
  * 生成されたyamlを実行すると、weaveコンテナが各ノードで立ちます。そのコンテナはインターネット経由でpullされます

### 手順を見つける手順 
* インターネットにつながる環境でKubernetesを構築します
* `kubectl version | base64 | tr -d '\n'`を実行した結果のbase64コードをメモします
* 次の2つを実行する手順を作ればOKです
  * `wget https://cloud.weave.works/k8s/net?k8s-version=<メモしたbase64>`を実行してyamlをダウンロード
  * そのyamlに含まれるイメージを`docker pull` & `docker save`でファイルに書き出し、搬送後に`docker load -i <ファイル>`する

# まとめ
* kubeadmを使用したオフライン環境での構築手順を前半に書きました
  * イメージのpullを行うために、オンライン環境にdockerが必要です
* その手順を見つけた方法を後半に書きました
  * 手順を見つけるには、オンライン環境にKubernetesを構築する必要があります[^6] 

[^1]: 使うOSイメージによってはパッケージが足りない可能性もあります。その場合は、[後半](#手順の見つけ方)の解説で必要なパッケージを見つけてください
[^2]: 厳密には一部のファイルはmasterにのみ必要なファイルなのですが、手順簡略化のためにnodeにも搬送する手順になっています
[^3]: 依存関係の把握にコマンドを使うことも考えましたが、debファイルのダウンロードURLを見つけるのにPakcage一覧が必要なためこの方法にしました
[^4]: Docker/Kubernetesの別アーキテクチャのパッケージを探す場合は次からたどって探してください
  Docker: https://download.docker.com/linux/
  Kubernetes: https://packages.cloud.google.com/
[^5]: 実は`kubeadm config image pull`でpullまでしてくれます。前半で解説したオフライン構築手順側はkubeadmのインストールを省略するためにこの方法は使っていません。理論上はソースコードを読めば`kubeadm config image list`の結果はkubeadmインストールなしでも分かるはずですが、構築した方がむしろ楽なので調べていません
[^6]: 前半で解説したオフライン構築手順側はkubernetesのインストールを省略するためにこの方法は使っていません。理論上はソースコードを読めば`kubectl version | base64 | tr -d '\n'`の結果はKubernetes構築なしでも分かるはずですが、構築した方がむしろ楽なので調べていません