コンテナ実践入門(Docker & Kubenates)

#コンテナ実践入門(Docker & Kubenates)
##1.Docker

Dockerを扱うにあたり、体系的にまとめないと忘れそうなことを記載。プログラムのsample等も。

・DockerfileではDocker独自のDSLを使ってイメージの構成を行う。
この際に指示句として指定するのがインストラクション(命令)と呼ばれる。

```ruby:Dockerfileの書き方&ビルドの仕方
FROM
 作成するDockerイメージのベースとなるイメージを指定する。
 FROMで取得するDockerイメージはDocker Hubに公開されているものである。DockerはデフォルトだとDocker Hubのレジストリを参照する。

RUN
 イメージビルドじにDockerコンテナ内で実行するコマンドを定義する。

COPY
 Dockerを動作させるホストマシンのファイルやディレクトリをコンテナ内にコピーする

CMD
 Dockerコンテナとして起動する際にコンテナ内で実行するプロセス(コマンド)を指定する。
 RUNはアプリケーションの更新や配置、CMDはアプリケーションを起動する処理と考える。

ENTRYPOINT


######################################
sample:起動する時にMSG出力するだけのコンテナのDockerfile
[root@master test]# cat Dockerfile 
FROM centos:latest
COPY helloworld /usr/local/bin
RUN  chmod 777 /usr/local/bin/helloworld
CMD ["helloworld"]
######################################

イメージビルドは下記で実行する。
[Dockerfileという名前のファイルを使う場合]
docker image build -t イメージ名[:タグ名] Dockerfile配置ディレクトリのパス

[Dockerfileという名前以外のファイルを使う場合]
docker image build -t イメージ名[:タグ名] -f Dockerfileが存在するディレクトリ名

ローカルにイメージがあるが敢えてレジストリから最新をDLする場合は、
--pull=trueを付与する。

例)
[root@master test]# docker image build -t hello:aaa `pwd`
Sending build context to Docker daemon 4.096 kB
Step 1/4 : FROM centos:latest
 ---> 9f38484d220f
Step 2/4 : COPY helloworld /usr/local/bin
 ---> Using cache
 ---> 3309df729322
Step 3/4 : RUN chmod 777 /usr/local/bin/helloworld
 ---> Using cache
 ---> 93e4fb39cb7b
Step 4/4 : CMD helloworld
 ---> Using cache
 ---> a58c80cba9a7
Successfully built a58c80cba9a7

イメージビルド後はイメージができていることを確認する
docker image ls

例)
[root@master test]# docker image ls 
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
helloworld                        latest              a58c80cba9a7        52 minutes ago      202 MB
hello                             aaa                 a58c80cba9a7        52 minutes ago      202 MB
```

・Docker Hubへのイメージの公開
インターネット上のDocker Hubへ個別イメージ展開

```ruby:DockerHubに対するpush
1.下記サイトで新規アカウント作成を実施する。
https://hub.docker.com/

2.アカウント情報をもとにDocker Hubへログイン
docker login -u ユーザ名 -p パスワード

3.pushしたいイメージに対してタグをつける。
docker tag イメージID DockerHubユーザ名/レポジトリ名:タグ名

4.Docker Hubへイメージpushする。
docker push DockerHubユーザ名/レポジトリ名:タグ名

```

・Dockerコンテナ起動(docker run)
コンテナ起動オプション

```ruby:コンテナ起動時によく使うパターン

通常パターン
docker run -h XXX --name YYY -itd イメージ名[:タグ名] 
・-iは標準入力を有効化するという意味、-tは仮想端末の生成。bashで操作するには-itで起動することが必須。
・-dはバックグランド起動
・-hはコンテナのホスト名指定
・-nはコンテナ名指定

ポートフォワーディングしたい場合
docker run -h XXX --name YYY -p ホスト側ポート:コンテナ側ポート -itd イメージ名[:タグ名]
・ホスト側のポートアクセスをDNATでコンテナ側ポートへ転送

ホストと共有したい永続ストレージを用意する場合
docker run -h XXX --name YYY -v ホスト側DIR:コンテナ側DIR -itd イメージ名[:タグ名]
・ホスト側DIR内へコンテナ側DIRをマウント。コンテナ削除されるとデータが消えるが、データを永続化できる

コンテナ停止時にコンテナ自動削除
docker run -h XXX --name YYY --rm -itd イメージ名[:タグ名]
・停止時にコンテナを残す必要がないものは削除してくれて便利

```


・Dockerプライベートレジストリを作りたい場合
DockerHubでは1つまでなら無料。
https://docs.docker.com/registry/deploying/

```ruby:Dockerプライベートレジストリ

1.プライベートレジストリ用途のコンテナを起動。イメージは永続化したいのでボリュームマウント。
これでポート5000で稼働するレジストリサーバ構築完了。自動起動もする。
docker run -d -p 5000:5000 --restart=always --name registry -v /mnt/registry:/var/lib/registry registry:2

2. 実際にイメージをpush&pull
テスト用イメージをDocker Hubからpull
docker pull ubuntu:16.04

pushできるようにタグ名を修正
docker tag ubuntu:16.04 localhost:5000/my-ubuntu

プライベートレジストリにpush
docker push localhost:5000/my-ubuntu

既存イメージ削除
docker image remove ubuntu:16.04
docker image remove localhost:5000/my-ubuntu

プライベートレジストリからpull
docker pull localhost:5000/my-ubuntu

```

・Mysql公式コンテナ起動方法

    ・/dataでデータは永続化する。
    ・管理者ユーザrootのパスワード指定
    docker run -v /data:/var/lib/mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD='P#ssw0rd' -d mysql:5.7

##2.Kubenates
簡単に言うと、Dockerなどコンテナを管理するコンテナオーケストレーションソフトウェア。
・コマンド１発で、コンテナを複製し、クラスタ環境を構築できる。
・Rolling Update(無停止更新)ができる
・Self-Healing可能。既定の台数に満たない場合は維持すべく新規でコンテナ起動するなどが自動化。

###Kubenatesを構成するコンポーネント
(1)_MasterNode_

__kube-apiserver__
Component on the master that exposes the Kubernetes API. It is the front-end for the Kubernetes control plane.
(Kubenetesのリソース情報(Pod似に関する情報やCluster IPなど)を管理。kube-proxyやkubeletなどのプロセスは、このAPI Serverを介して、お互いの情報をやり取りする。)

__etcd__
Consistent and highly-available key value store used as Kubernetes’ backing store for all cluster data.

__kube-scheduler__
Component on the master that watches newly created pods that have no node assigned, and selects a node for them to run on.

__kube-controller-manager__
Logically, each controller is a separate process, but to reduce complexity, they are all compiled into a single binary and run in a single process.

* Node Controller: Responsible for noticing and responding when nodes go down.
* Replication Controller: Responsible for maintaining the correct number of pods for every replication controller object in the system.
* Endpoints Controller: Populates the Endpoints object (that is, joins Services & Pods).
* Service Account & Token Controllers: Create default accounts and API access tokens for new namespaces.

(2)_Node_

__参考__
https://kubernetes.io/docs/concepts/overview/components/
https://tech-lab.sios.jp/archives/7745#Kubernetes

###Kubenates環境構築手順

Kubenatesの構築方法にはいくつか方法があるが、
今回は便利な構築ツールであるkubeadmで初期構築を実施する。

__1.kubeadmインストール__
https://kubernetes.io/ja/docs/setup/independent/install-kubeadm/

```ruby:rpmパッケージインストール/SELINUXの無効化/カーネルパラメータの設定(全ノードで実施)
yum -y install docker
systemctl enable --now docker

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF

# Set SELinux in permissive mode (effectively disabling it)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet

#CentOS/RHEL7のみ(iptablesの不具合対応)
cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

#swap無効化
swapoff -a && swapon -s
```

__2.kubeadmを使用したシングルクラスター構築__

Master ノードで初期セットアップする
[apiserver-advertise-address] には Kubernetes API サーバーがリスンする IP アドレスを指定する。
[--pod-network-cidr] には、Pod Network が利用するネットワークを指定します。Pod Network を構成するためのプラグインはいくつかのソフトウェアから選択可能。(詳細は下記リンク参照) 
https://kubernetes.io/docs/concepts/cluster-administration/networking/ 

下記例ではFlannelを利用。10.244.0.0/16固定。

```ruby:Masterノードで初期セットアップ(MasterNodeで実施)

#マスター初期セットアップ
kubeadm init --apiserver-advertise-address=[マスターノードIPアドレス] --pod-network-cidr=10.244.0.0/16 

#認証情報をkubectlを利用したいユーザのホームディレクトリにコピー
mkdir -p $HOME/.kube 
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config 
chown $(id -u):$(id -g) $HOME/.kube/config 

#Flannelにおける初期構成実施
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml 
```

上記実施後に出力された下記のようなコマンドを各WorkerNodeで実行する。クラスターへのJoin処理。
kubeadm join [マスターノードIPアドレス]:6443 --token xxxxxxxxxxxx ¥
--discovery-token-ca-cert-hash XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

この後にノードが正常にクラスターに追加されていることを確認する

```ruby:クラスター参加ノード確認
kubectl get nodes

#Statusが[Ready]になっていることを確認する
[root@master0 ~]# kubectl get nodes
NAME      STATUS   ROLES    AGE   VERSION
master0   Ready    master   19h   v1.15.0
node1     Ready    <none>   19h   v1.15.0
node2     Ready    <none>   19h   v1.15.0
```