Kubernetesをソースコードからビルドしてローカル環境にkubernetes clusterを構築する

## はじめに

以下の手順は、CentOS7上で、Kubernetesをソースコードからビルドして、ローカル環境にクラスタを構築する手順です。


## 事前準備

### Go言語のバージョンを1.7以上にする
contextパッケージが必要となりますが、バージョン1.7以上ではない場合同梱されていないということで、Go言語のバージョンをアップデートします。
入手元: https://golang.org/doc/install

```bash
# tar -C /usr/local -xzf go1.8.linux-amd64.tar.gz
# export PATH=$PATH:/usr/local/go/bin
```

なお、次で説明する方法と同じように、Go自体のバージョンを上げるのではなく、contextパッケージのみをダウンロードしてきてPATHを設定する方法でも大丈夫だと思います。

### cfssl, cfssljsonパッケージを追加する
ローカルクラスタを起動するために必要となるパッケージです。
これらのパッケージがインストールされていないと、クラスタ起動時に以下のエラーが発生します。
Hintに記載されているコマンドを使って、PATHのexportと、パッケージの入手をしておきます。
https://github.com/cloudflare/cfssl

```bash
Failed to successfully run 'cfssl', please verify that cfssl and cfssljson are in $PATH.
Hint: export PATH=$PATH:$GOPATH/bin; go get -u github.com/cloudflare/cfssl/cmd/...
```


なお、Go言語の環境変数は以下のコマンドで確認できます。

```bash
# go env 
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/root/go"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build134608843=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
```

### 作業ディレクトリ
移行の作業は、全てkubernetesのソースコードフォルダ配下で実行します。ここでは、/opt/git/kubernetes以下となります。

```bash
# pwd
/opt/git/kubernetes
```

## 環境構築

### etcdをセットアップする
ローカルクラスタを実行する前提として、etcdがインストールされている必要があります。用意されているスクリプトを実行して、etcdをインストールし、PATHをexportします。

```bash
# ./hack/install-etcd.sh 
Downloading https://github.com/coreos/etcd/releases/download/v3.0.14/etcd-v3.0.14-linux-amd64.tar.gz succeed
etcd v3.0.14 installed. To use:
export PATH=/opt/git/kubernetes/third_party/etcd:${PATH}.
# export PATH=/opt/git/kubernetes/third_party/etcd:${PATH}
```

### ローカルクラスタを起動する
local-up-cluster.shを使用して、ローカルクラスタを起動します。なお起動に必要なコマンド群は、自動的にビルドされます。

```bash
# ./hack/local-up-cluster.sh 
make: Entering directory `/opt/git/kubernetes'
make[1]: Entering directory `/opt/git/kubernetes'
make[1]: Leaving directory `/opt/git/kubernetes'
make[1]: Entering directory `/opt/git/kubernetes'
make[1]: Leaving directory `/opt/git/kubernetes'
+++ [0221 20:09:36] Building the toolchain targets:
    k8s.io/kubernetes/hack/cmd/teststale
    k8s.io/kubernetes/vendor/github.com/jteeuwen/go-bindata/go-bindata
+++ [0221 20:09:37] Generating bindata:
    test/e2e/generated/gobindata_util.go
/opt/git/kubernetes /opt/git/kubernetes/test/e2e/generated
/opt/git/kubernetes/test/e2e/generated
+++ [0221 20:09:38] Building go targets for linux/amd64:
    cmd/kubectl
    cmd/hyperkube
    vendor/k8s.io/kube-aggregator
make: Leaving directory `/opt/git/kubernetes'
 WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.
Kubelet cgroup driver defaulted to use: systemd
API SERVER insecure port is free, proceeding...
API SERVER secure port is free, proceeding...
Detected host and ready to start services.  Doing some housekeeping first...
Using GO_OUT /opt/git/kubernetes/_output/local/bin/linux/amd64
Starting services now!
Starting etcd
etcd --advertise-client-urls http://127.0.0.1:2379 --data-dir /tmp/tmp.BCTwiX1Q3Y --listen-client-urls http://127.0.0.1:2379 --debug > "/dev/null" 2>/dev/null
Waiting for etcd to come up.
+++ [0221 20:09:49] On try 2, etcd: : http://127.0.0.1:2379
{"action":"set","node":{"key":"/_test","value":"","modifiedIndex":4,"createdIndex":4}}
Generating a 2048 bit RSA private key
...........+++
..+++
writing new private key to '/var/run/kubernetes/server-ca.key'
-----
Generating a 2048 bit RSA private key
....................................................+++
............+++
writing new private key to '/var/run/kubernetes/client-ca.key'
-----
Generating a 2048 bit RSA private key
.......................................................................+++
.......................................................................+++
writing new private key to '/var/run/kubernetes/request-header-ca.key'
-----
2017/02/21 20:09:50 [INFO] generate received request
2017/02/21 20:09:50 [INFO] received CSR
2017/02/21 20:09:50 [INFO] generating key: rsa-2048
2017/02/21 20:09:52 [INFO] encoded CSR
2017/02/21 20:09:52 [INFO] signed certificate with serial number 124466083292368969753878751531462897150884477228
2017/02/21 20:09:52 [INFO] generate received request
2017/02/21 20:09:52 [INFO] received CSR
2017/02/21 20:09:52 [INFO] generating key: rsa-2048
2017/02/21 20:09:52 [INFO] encoded CSR
2017/02/21 20:09:52 [INFO] signed certificate with serial number 631329441025824396392927159183757173624650656295
2017/02/21 20:09:52 [INFO] generate received request
2017/02/21 20:09:52 [INFO] received CSR
2017/02/21 20:09:52 [INFO] generating key: rsa-2048
2017/02/21 20:09:52 [INFO] encoded CSR
2017/02/21 20:09:52 [INFO] signed certificate with serial number 701426569215378577074384681992288543339367856691
2017/02/21 20:09:52 [INFO] generate received request
2017/02/21 20:09:52 [INFO] received CSR
2017/02/21 20:09:52 [INFO] generating key: rsa-2048
2017/02/21 20:09:53 [INFO] encoded CSR
2017/02/21 20:09:53 [INFO] signed certificate with serial number 229862793080566960970445958651876853638005750287
2017/02/21 20:09:53 [INFO] generate received request
2017/02/21 20:09:53 [INFO] received CSR
2017/02/21 20:09:53 [INFO] generating key: rsa-2048
2017/02/21 20:09:54 [INFO] encoded CSR
2017/02/21 20:09:54 [INFO] signed certificate with serial number 36416734191975628719770341690511488840046660423
2017/02/21 20:09:54 [INFO] generate received request
2017/02/21 20:09:54 [INFO] received CSR
2017/02/21 20:09:54 [INFO] generating key: rsa-2048
2017/02/21 20:09:54 [INFO] encoded CSR
2017/02/21 20:09:54 [INFO] signed certificate with serial number 553207743375559129377582195944191786742425990488
2017/02/21 20:09:54 [INFO] generate received request
2017/02/21 20:09:54 [INFO] received CSR
2017/02/21 20:09:54 [INFO] generating key: rsa-2048
2017/02/21 20:09:56 [INFO] encoded CSR
2017/02/21 20:09:56 [INFO] signed certificate with serial number 117212563773423357457144032620109324825346970515
2017/02/21 20:09:56 [INFO] generate received request
2017/02/21 20:09:56 [INFO] received CSR
2017/02/21 20:09:56 [INFO] generating key: rsa-2048
2017/02/21 20:09:57 [INFO] encoded CSR
2017/02/21 20:09:57 [INFO] signed certificate with serial number 66524454669338354068916931456157096264836067124
2017/02/21 20:09:57 [INFO] generate received request
2017/02/21 20:09:57 [INFO] received CSR
2017/02/21 20:09:57 [INFO] generating key: rsa-2048
2017/02/21 20:09:58 [INFO] encoded CSR
2017/02/21 20:09:58 [INFO] signed certificate with serial number 472293545949172374356825841988836525612842141668
Waiting for apiserver to come up
+++ [0221 20:09:59] On try 2, apiserver: : {
  "major": "1",
  "minor": "6+",
  "gitVersion": "v1.6.0-alpha.3.346+b201ac2f8f8328-dirty",
  "gitCommit": "b201ac2f8f8328d9c828f36358b106d0ea21a14a",
  "gitTreeState": "dirty",
  "buildDate": "2017-02-22T00:50:02Z",
  "goVersion": "go1.8",
  "compiler": "gc",
  "platform": "linux/amd64"
}
Error from server (AlreadyExists): namespaces "kube-public" already exists
Cluster "local-up-cluster" set.
use 'kubectl --kubeconfig=/var/run/kubernetes/admin-kube-aggregator.kubeconfig' to use the aggregated API server
kubelet ( 13513 ) is running.
Local Kubernetes cluster is running. Press Ctrl-C to shut it down.

Logs:
  /tmp/kube-apiserver.log
  /tmp/kube-controller-manager.log
  /tmp/kube-proxy.log
  /tmp/kube-scheduler.log
  /tmp/kubelet.log

To start using your cluster, you can open up another terminal/tab and run:

  export KUBECONFIG=/var/run/kubernetes/admin.kubeconfig
  cluster/kubectl.sh

Alternatively, you can write to the default kubeconfig:

  export KUBERNETES_PROVIDER=local

  cluster/kubectl.sh config set-cluster local --server=https://localhost:6443 --certificate-authority=/var/run/kubernetes/server-ca.crt
  cluster/kubectl.sh config set-credentials myself --client-key=/var/run/kubernetes/client-admin.key --client-certificate=/var/run/kubernetes/client-admin.crt
  cluster/kubectl.sh config set-context local --cluster=local --user=myself
  cluster/kubectl.sh config use-context local
  cluster/kubectl.sh
```



### ビルド済みのバイナリを使用してクラスタを起動する
事前にコマンド群をビルドしておき、それらを使用してクラスタを起動することも出来ます。
まずは、必要なコマンド群をmakeで作成します。

```bash
# make WHAT='cmd/kubectl cmd/hyperkube test/e2e/e2e.test';
```

次に、作成したコマンドが格納されているフォルダを引数にとって、local-up-cluster.shを実行します。

```bash
# ./hack/local-up-cluster.sh -o _output/bin/
skipping build
using source _output/bin/
skipped the build.
 WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.
Kubelet cgroup driver defaulted to use: systemd
API SERVER insecure port is free, proceeding...
API SERVER secure port is free, proceeding...
Detected host and ready to start services.  Doing some housekeeping first...
Using GO_OUT _output/bin/
Starting services now!
Starting etcd
etcd --advertise-client-urls http://127.0.0.1:2379 --data-dir /tmp/tmp.GVYitifLmI --listen-client-urls http://127.0.0.1:2379 --debug > "/dev/null" 2>/dev/null
Waiting for etcd to come up.
+++ [0221 20:24:34] On try 2, etcd: : http://127.0.0.1:2379
{"action":"set","node":{"key":"/_test","value":"","modifiedIndex":4,"createdIndex":4}}
Generating a 2048 bit RSA private key
...+++
.....+++
writing new private key to '/var/run/kubernetes/server-ca.key'
-----
Generating a 2048 bit RSA private key
............................+++
................................+++
writing new private key to '/var/run/kubernetes/client-ca.key'
-----
Generating a 2048 bit RSA private key
..................+++
..........................................+++
writing new private key to '/var/run/kubernetes/request-header-ca.key'
-----
2017/02/21 20:24:34 [INFO] generate received request
2017/02/21 20:24:34 [INFO] received CSR
2017/02/21 20:24:34 [INFO] generating key: rsa-2048
2017/02/21 20:24:35 [INFO] encoded CSR
2017/02/21 20:24:35 [INFO] signed certificate with serial number 447052118705216540313463589978670235143017346168
2017/02/21 20:24:35 [INFO] generate received request
2017/02/21 20:24:35 [INFO] received CSR
2017/02/21 20:24:35 [INFO] generating key: rsa-2048
2017/02/21 20:24:35 [INFO] encoded CSR
2017/02/21 20:24:35 [INFO] signed certificate with serial number 453147652717934396244790326985575891492885267463
2017/02/21 20:24:35 [INFO] generate received request
2017/02/21 20:24:35 [INFO] received CSR
2017/02/21 20:24:35 [INFO] generating key: rsa-2048
2017/02/21 20:24:35 [INFO] encoded CSR
2017/02/21 20:24:35 [INFO] signed certificate with serial number 272097984252071207959056508542467462400256844015
2017/02/21 20:24:35 [INFO] generate received request
2017/02/21 20:24:35 [INFO] received CSR
2017/02/21 20:24:35 [INFO] generating key: rsa-2048
2017/02/21 20:24:36 [INFO] encoded CSR
2017/02/21 20:24:36 [INFO] signed certificate with serial number 89416123288674897438978570927840403417394925806
2017/02/21 20:24:36 [INFO] generate received request
2017/02/21 20:24:36 [INFO] received CSR
2017/02/21 20:24:36 [INFO] generating key: rsa-2048
2017/02/21 20:24:36 [INFO] encoded CSR
2017/02/21 20:24:36 [INFO] signed certificate with serial number 463788683463756580938211377131316447800974180111
2017/02/21 20:24:36 [INFO] generate received request
2017/02/21 20:24:36 [INFO] received CSR
2017/02/21 20:24:36 [INFO] generating key: rsa-2048
2017/02/21 20:24:36 [INFO] encoded CSR
2017/02/21 20:24:36 [INFO] signed certificate with serial number 686663176438254195071220868931395298199838761704
2017/02/21 20:24:37 [INFO] generate received request
2017/02/21 20:24:37 [INFO] received CSR
2017/02/21 20:24:37 [INFO] generating key: rsa-2048
2017/02/21 20:24:37 [INFO] encoded CSR
2017/02/21 20:24:37 [INFO] signed certificate with serial number 46503830313797068101462792228458221275331011435
2017/02/21 20:24:37 [INFO] generate received request
2017/02/21 20:24:37 [INFO] received CSR
2017/02/21 20:24:37 [INFO] generating key: rsa-2048
2017/02/21 20:24:38 [INFO] encoded CSR
2017/02/21 20:24:38 [INFO] signed certificate with serial number 581841164489590118531163072166076612807454584041
2017/02/21 20:24:38 [INFO] generate received request
2017/02/21 20:24:38 [INFO] received CSR
2017/02/21 20:24:38 [INFO] generating key: rsa-2048
2017/02/21 20:24:38 [INFO] encoded CSR
2017/02/21 20:24:38 [INFO] signed certificate with serial number 2683591120418327848777775490762990201349172159
Waiting for apiserver to come up
+++ [0221 20:24:39] On try 2, apiserver: : {
  "major": "1",
  "minor": "6+",
  "gitVersion": "v1.6.0-alpha.3.346+b201ac2f8f8328-dirty",
  "gitCommit": "b201ac2f8f8328d9c828f36358b106d0ea21a14a",
  "gitTreeState": "dirty",
  "buildDate": "2017-02-22T00:50:02Z",
  "goVersion": "go1.8",
  "compiler": "gc",
  "platform": "linux/amd64"
}
Error from server (AlreadyExists): namespaces "kube-public" already exists
Cluster "local-up-cluster" set.
use 'kubectl --kubeconfig=/var/run/kubernetes/admin-kube-aggregator.kubeconfig' to use the aggregated API server
kubelet ( 16937 ) is running.
Local Kubernetes cluster is running. Press Ctrl-C to shut it down.

Logs:
  /tmp/kube-apiserver.log
  /tmp/kube-controller-manager.log
  /tmp/kube-proxy.log
  /tmp/kube-scheduler.log
  /tmp/kubelet.log

To start using your cluster, you can open up another terminal/tab and run:

  export KUBECONFIG=/var/run/kubernetes/admin.kubeconfig
  cluster/kubectl.sh

Alternatively, you can write to the default kubeconfig:

  export KUBERNETES_PROVIDER=local

  cluster/kubectl.sh config set-cluster local --server=https://localhost:6443 --certificate-authority=/var/run/kubernetes/server-ca.crt
  cluster/kubectl.sh config set-credentials myself --client-key=/var/run/kubernetes/client-admin.key --client-certificate=/var/run/kubernetes/client-admin.crt
  cluster/kubectl.sh config set-context local --cluster=local --user=myself
  cluster/kubectl.sh config use-context local
  cluster/kubectl.sh
```

### ノードの起動を確認する
構築したKubernetes環境を利用するには、cluster/kubectl.shを使用します。

```bash
# cluster/kubectl.sh get node
NAME        STATUS    AGE       VERSION
127.0.0.1   Ready     2s        v1.6.0-alpha.3.346+b201ac2f8f8328-dirty
```

### PODを作成する

```bash
# cluster/kubectl.sh create -f test.yaml
```