IBM Cloud Private-CE の Kubernetes とコンテナ・リポジトリのCLI基本操作 


自宅の開発サーバーや、会社の開発チームのワークグループサーバーなど、部屋の片隅に置いたサーバーに、IBM Cloud Private Community Edition (以下、ICP-CEとする) をインストールして、アプリを開発を体験してみようよ。という発想で書いたものです。  本番サービスを提供するには、パブリック・クラウドのk8s環境が、やっぱり楽だよね。ってことで軽く書いています。



## Vagrantの仮想サーバーの準備

ローカルに、dockerコンテナをビルドする環境や、bxやkubecltのオペレーション環境を作るために、vagrantを利用しました。 目的に合わせた環境をオートマティックに作るために Vagrantfile を作成して、最新化と改良を繰り返しながら熟成した Vagrantfile をGitHubに登録しています。 今回も自分のGitHubからクローンして、利用することにします。 

Vagrantの環境が出来ていれば、以下の３ステップで、Ubuntu Linux 16.04 に、docker-ce, kubectl, bxなどの最新版が入った仮想サーバーが起動します。

~~~
git clone https://github.com/takara9/bluemix-dev test-icp
cd test-icp
vagrant up
~~~


参考資料: 
* Bluemixコマンドのインストール [Getting started with IBM Cloud CLI](https://console.bluemix.net/docs/cli/reference/bluemix_cli/get_started.html#getting-started)
* Docker CEのインストール  [Docker CE / Download](https://www.docker.com/community-edition#/download)
* kubectlコマンドのインストール [Install and Set Up kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
* Vagrantのインストール [Download Vagrant](https://www.vagrantup.com/downloads.html)
* VirtualBoxのインストール [VirtualBox](https://www.virtualbox.org/)



## ICP-CE のbxコマンドの準備
vagrantでローカルで起動したLinuxに、`vagrant ssh`でログインできたら、bxコマンドの IBM Cloud Privateプラグインをインストールします。

下記の様にICP-CEのウェブページにログして、Cloud Private CLI へ移動します。

![スクリーンショット 2018-02-20 9.57.49.png](https://qiita-image-store.s3.amazonaws.com/0/42829/8cacbc95-9845-beae-89ed-e818f7fecf0c.png "スクリーンショット 2018-02-20 9.57.49.png")

次のスクリーン・ショットの中で、DOWNLOAD FOR LINUX (64bit)で、リンクのURLをコピーします。

![スクリーンショット 2018-02-20 18.40.16.png](https://qiita-image-store.s3.amazonaws.com/0/42829/d77b31d3-c217-84ba-b7bc-41208e646f4b.png "スクリーンショット 2018-02-20 18.40.16.png")

先ほどログインしたLinuxのターミナル上で、次の様に、プラグインをダウンロードします。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ curl -k -LO https://192.168.1.100:8443/api/cli/icp-linux-amd64
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 19.5M  100 19.5M    0     0  79.5M      0 --:--:-- --:--:-- --:--:-- 79.9M
~~~

bxコマンドで、プラグインをインストールします。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ bx plugin install icp-linux-amd64
Installing binary...
OK
Plug-in 'icp 2.1.284' was successfully installed into /home/vagrant/.bluemix/plugins/icp. Use 'bx plugin show icp' to show its details.
~~~

確認としてプラグインのヘルプを表示してみます。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ bx plugin show icp
                                  
Plugin                         icp   
Version                        2.1.284   
SDK Version                       
Minimal CLI version required   0.4.9   

Commands:
pr api                 View the API endpoint and API version for the service.   
pr cluster-config      Download the Kubernetes configuration and configure kubectl for a specified cluster.   
pr cluster-get         View details for a cluster.   
pr clusters            List all the clusters in your account.   
pr delete-helm-chart   Deletes a Helm chart from the IBM Cloud Private internal registry.   
pr init                Initialize the IBM Cloud Private plugin with the API endpoint.   
pr load-helm-chart     Loads a Helm chart archive to an IBM Cloud Private cluster.   
pr load-ppa-archive    Load Docker images and Helm charts compressed file that you downloaded from Passport Advantage.   
pr login               Log user in.   
pr logout              Log user out.   
pr master-get          View the details about a master node.   
pr masters             List all master nodes in an existing cluster.   
pr tokens              Display the oauth tokens for the current session. Run bx pr login to retrieve the tokens.   
pr worker-get          View the details about a worker node.   
pr workers             List all worker nodes in an existing cluster.   
~~~


## bxコマンドで ICP-CEへログイン

IPアドレスの部分は、自分の環境に置き換えて実行します。`--skip-ssl-validation`は、独自の認証局が発行した証明書でもパスする様に指定します。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ bx pr login -a https://192.168.1.100:8443 --skip-ssl-validation
API endpoint: https://192.168.1.100:8443

Username> admin

Password> 
Authenticating...
OK

Select an account:
1. ICP Account (dcf61fd7b0971a2ef7ceb4faae004db7)
Enter a number> 1
Targeted account: ICP Account (dcf61fd7b0971a2ef7ceb4faae004db7)
~~~


## クラスタの表示

パブリッククラウドでは、`bx cs clusters` となりますが、cs を pr に置き換えた形で利用できます。 下記の表示で Workersのカラムが 0 になっていますね。 表示が変ですが、気にせず先へ進めます。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ bx pr clusters
OK
Name        ID                                 State      Created                    Masters   Workers   Datacenter   
mycluster   00000000000000000000000000000001   deployed   2018-02-18T15:20:06+0000   1         0         default   
~~~


クライアント側の kubectlコマンドが ICP-CEへ接続できる様に、次のコマンドを実行します。　bx cs では環境変数が表示されるだけで、シェルに反映してくれませんでしたが、bx pr では、この後、すぐにkubectlが動作する様になります。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ bx pr cluster-config mycluster
Configuring kubectl: /home/vagrant/.bluemix/plugins/icp/clusters/mycluster/kube-config
Cluster "mycluster" set.
Context "mycluster-context" created.
User "mycluster-user" set.
Context "mycluster-context" modified.
Switched to context "mycluster-context".

OK
Cluster mycluster configured successfully.
~~~


kubectlを実行してみます。先ほど、ワーカー・ノードがゼロになっていましたが、`kubectl get node`ではどうなっているでしょうか？

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ kubectl get node
NAME            STATUS    ROLES     AGE       VERSION
192.168.1.100   Ready     <none>    1d        v1.8.3+icp
~~~

ちゃんと、ノードのIPアドレスや状態が表示されました。（良かった）
次にk8sのクラスタのdefaultネームスペースを表示してみます。 

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ kubectl get all
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
svc/kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP   1d
~~~





## WebUIへのアクセス

k8sのWebUIを表示するために、プロキシを立ち上げて、ダッシュボードを表示してみます。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ kubectl proxy --address='0.0.0.0'
Starting to serve on [::]:8001
~~~


ブラウザで、`http://localhost:8001`をアクセスしたところ、次の様な表示が出てきました。デフォルトではk8sのダッシュボードが止められている様ですね。

![スクリーンショット 2018-02-20 10.34.08.png](https://qiita-image-store.s3.amazonaws.com/0/42829/6fd33c10-20bc-5c31-3c5f-3d5daec1d080.png "スクリーンショット 2018-02-20 10.34.08.png")





## 最小のデプロイメントの実行

YAMLなしでも起動できる対話モードでデプロイメントを起動してみます。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ kubectl run -it --image ubuntu:latest bash-client
If you don't see a command prompt, try pressing enter.
root@bash-client-84bb76f87b-2l7ps:/# 
root@bash-client-84bb76f87b-2l7ps:/# pwd
/
root@bash-client-84bb76f87b-2l7ps:/# hostname
bash-client-84bb76f87b-2l7ps

root@bash-client-84bb76f87b-2l7ps:/# exit
exit
Session ended, resume using 'kubectl attach bash-client-84bb76f87b-2l7ps -c bash-client -i -t' command when the pod is running
~~~

一旦ログアウトした後に、再度、コンテナへログインします。 

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ kubectl attach -it bash-client-84bb76f87b-2l7ps -c bash-client 
If you don't see a command prompt, try pressing enter.
root@bash-client-84bb76f87b-2l7ps:/# 
root@bash-client-84bb76f87b-2l7ps:/# pwd
/
root@bash-client-84bb76f87b-2l7ps:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@bash-client-84bb76f87b-2l7ps:/# hostname
bash-client-84bb76f87b-2l7ps
~~~




## ICP-CEのコンテナ・リポジトリの利用

ICP-CEの中に作られているコンテナ・リポジトリを利用してみます。 コンテナ・リポジトリにログインするには、証明書が必要となります。　そこで、ICP-CEの証明書のコピーを、ローカルのDockerコンテナ環境にコピーします。 この証明書は、config.yamlに定義され cluster_CA_domain の名前でアクセスする必要があります。このため、hostsにエントリーを追加します。


参考資料: [Configuring authentication for the Docker CLI](https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/manage_images/configuring_docker_cli.html)



### /etc/hostsにエントリーを追加

vagrantで起動したLinuxの/etc/hostsに、以下のエントリーを追加します。 IPアドレスは、自身の環境で置き換えてください。

~~~/etc/hosts
192.168.1.100 mycluster.icp
~~~



### 証明書をローカルのdockerの設定に追加

vagrantで起動したLinuxのDocker環境へ、ICP-CEの同ディレクトリから、ca.crtをコピーします。 

~~~
root@vagrant-ubuntu-trusty-64:/etc/docker# pwd
/etc/docker
root@vagrant-ubuntu-trusty-64:/etc/docker# mkdir certs.d
root@vagrant-ubuntu-trusty-64:/etc/docker# cd certs.d/
root@vagrant-ubuntu-trusty-64:/etc/docker/certs.d# mkdir mycluster.icp:8500
root@vagrant-ubuntu-trusty-64:/etc/docker/certs.d# cd mycluster.icp\:8500/
root@vagrant-ubuntu-trusty-64:/etc/docker/certs.d/mycluster.icp:8500# cat - > ca.crt
~~~


### ICP-CEにあるリポジトリへログイン

リポジトリのドメイン名をhostsファイルへ追加、および、ca.crtのコピーで、dockerコマンドでのログインが可能となります。 ログインするには、IPアドレスではなく、hostsに登録したドメイン名とポート番号を付加した形式で、ターゲットを指定します。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ docker login mycluster.icp:8500 
Username: admin
Password: 
Login Succeeded
~~~

ICP-CEの Dockerリポジトリ にログインできたら、次は、カスタム・コンテナをビルドして、リポジトリ登録します。



### カスタム・コンテナのICP-CEリポジトリへ登録

パブリックの IBM Cloud Kubernetesのサービスと登録の流れは、まったく同じです。 コンテナをビルドして、ローカルのリポジトリにタグを付けてプッシュするだけですが、ネームスペースの設定方法が異なる点が注意です。

参考資料: [Pushing and pulling images](https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/manage_images/using_docker_cli.html)

簡潔に進めるため、カスタム・コンテナをビルドする材料をGitHubからクローンします。 kubectl get namespaces で利用できるネームスペースを確認して、タグを付与し、プッシュします。

~~~
vagrant@vagrant-ubuntu-trusty-64:~$ git clone https://github.com/takara9/web-nginx
Cloning into 'web-nginx'...
remote: Counting objects: 10, done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 10 (delta 0), reused 10 (delta 0), pack-reused 0
Unpacking objects: 100% (10/10), done.
Checking connectivity... done.

vagrant@vagrant-ubuntu-trusty-64:~$ cd web-nginx/

vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ docker build -t first-apl -f Dockerfile .
Sending build context to Docker daemon  161.8kB
Step 1/2 : FROM nginx:latest
latest: Pulling from library/nginx
8176e34d5d92: Pull complete 
cb1142c3ae99: Pull complete 
45b531966c63: Pull complete 
Digest: sha256:0ffc09487404ea43807a1fd9e33d9e924d2c8b48a7b7897e4d1231a396052ff9
Status: Downloaded newer image for nginx:latest
 ---> 9e988ed19567
Step 2/2 : ADD ./html /usr/share/nginx/html
 ---> fc2947938290
Successfully built fc2947938290
Successfully tagged first-apl:latest

vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
first-apl           latest              fc2947938290        5 seconds ago       109MB
nginx               latest              9e988ed19567        2 days ago          109M
~~~

ここから、上記のローカルのリポジトリにあるコンテナ first-apl をICP-CEのリポジトリへ登録していきます。namespaceは、defaultを利用します。

~~~
vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ kubectl get namespaces
NAME          STATUS    AGE
default       Active    1d
kube-public   Active    1d
kube-system   Active    1d
services      Active    1d


vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ docker tag first-apl:latest mycluster.icp:8500/default/first-apl:latest

vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ docker push mycluster.icp:8500/default/first-apl:latest
The push refers to repository [mycluster.icp:8500/default/first-apl]
dc27ca20df6f: Pushed 
d61b50fc25e4: Pushed 
d6490d020d9a: Pushed 
014cf8bfcb2d: Pushed 
latest: digest: sha256:8eced2f48518ed9c52b2147683021cd0b08ad2035b98d6fc4c7eb1735ed5b92b size: 1157

vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ kubectl get images
NAME        AGE
first-apl   28s
~~~


上記の様に、イメージを登録した結果は、`kubectl get images`でリストする事ができます。 パプリッククラウドでは `bx cr images` としました。


## デプロイメントの実行

前述の部分で登録したコンテナをデプロイメントとして、実行してみましょう。　最初にデプロイメントのYAMLを準備します。 spec.containers.image に注目してください。 `mycluster.icp:8500/default/first-apl:latest` が今回登録したコンテナのリポジトリ名になります。

~~~file:deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: first-apl
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: first-apl
    spec:
      containers:
      - name: first-apl-container
        image: mycluster.icp:8500/default/first-apl:latest
        ports:
        - containerPort: 80
~~~

上記のファイルを指定して、デプロイメントを作成して、コンテナを実行します。 約30秒ほどで起動しました。

~~~
vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ kubectl create -f deployment.yaml
deployment "first-apl" created

vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ kubectl get deploy
NAME          DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
bash-client   1         1         1            1           5h
first-apl     1         1         1            1           29s
~~~


## サービスの作成

サービスを作成して、MacBookからアクセスしてみます。


### NodePortでの公開

NodePortでサービスをサーバー外に公開するために、以下のYAMLファイルを準備します。

~~~file:service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: first-apl-svc
spec:
  type: NodePort
  selector:
    app: first-apl
  ports:
  - protocol: TCP
    port: 80
~~~    
    
次のコマンドでサービスを作成します。 CLUSTER-IPは `config.yaml`の `service_cluster_ip_range: 10.0.0.1/24`の設定に従って付与されます。
    
~~~
vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ kubectl create -f service.yaml 
service "first-apl-svc" created

vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ kubectl get svc
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
first-apl-svc   NodePort    10.0.0.116   <none>        80:31580/TCP   25s
kubernetes      ClusterIP   10.0.0.1     <none>        443/TCP        1d
~~~

ブラウザからアクセスすると、次の様に表示されました。 

![スクリーンショット 2018-02-20 15.55.13.png](https://qiita-image-store.s3.amazonaws.com/0/42829/61a56322-41de-12b6-6ade-aaac579c5199.png "スクリーンショット 2018-02-20 15.55.13.png")


### LoadBalancer での公開

残念ながら、ICP-CEでは、サービスとして、LoadBalancerはサポートされていませんでした。 

参照先：[Known issues and limitations](https://www.ibm.com/support/knowledgecenter/SSBS6K_2.1.0/getting_started/known_issues.html#2101) 

> Federation clusters do not support load discovery
Federation in IBM Cloud Private does not support service discovery across clusters. Federation feature in the Kubernetes community supports service of LoadBalancer type only. IBM Cloud Private does not support the LoadBalancer service type.


実際に指定したらどうなるのか、やってみました。

まず、次はロードバランサーのYAMLです。

~~~file:service-lb.yaml
apiVersion: v1
kind: Service
metadata:
  name: first-apl-lb
spec:
  type: LoadBalancer
  clusterIP: 10.0.0.200
  loadBalancerIP: 192.168.1.105
  selector:
    app: first-apl-svc
  ports:
  - protocol: TCP
    port: 31580
    targetPort: 80
~~~


このYAMLを適用した結果が以下です。  EXTERNAL-IP上記の `loadBalancerIP: 192.168.1.105`がセットされる必要がありますが、何時間たっても <pending>のままで、192.168.105をアクセスしても、表示されませんでした。

~~~
vagrant@vagrant-ubuntu-trusty-64:~/web-nginx$ kubectl get svc
NAME            TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)        AGE
first-apl-lb    LoadBalancer   10.0.0.138   <pending>     80:31145/TCP   15s
first-apl-svc   NodePort       10.0.0.116   <none>        80:31580/TCP   4m
kubernetes      ClusterIP      10.0.0.1     <none>        443/TCP        1d
~~~




## さいごに
LoadBalancerが提供されない点は、ちょっと残念でしたが、開発環境として利用するのであれば、NodePortもiptablesを利用してランダムなリクエストの分配を実施しているため、問題なく利用できると思います。それから、インハウスで開発する場合には、プライペート・リポジトリは便利ですね。

ICP-CEの基本的な使い方が解ったので、次はストレージについて調べてみようと思います。