はじめてのACS

事情によりやってみた備忘録です。
（AKSじゃないのかよというツッコミは甘んじてうけます）
これから新規ならAKSがいいかとおもいます。
https://docs.microsoft.com/ja-jp/azure/aks/acs-aks-migration

### ACSたてる

・目的のサブスクリプションなことを確認

```
az account list
az account show
```

・違ってたらset

```
az account set --subscription xxxx-xxxx....
```

・リソースグループ作る

```
# az group create --name $my_resouce_grp --location japaneast
```

・ACSクラスタつくる

```
# az acs create --orchestrator-type kubernetes --resource-group $my_resouce_grp --name $my-acs-cluster --generate-ssh-keys
SSH key files '/root/.ssh/id_rsa' and '/root/.ssh/id_rsa.pub' have been generated under ~/.ssh to allow SSH access to the VM. If using machines without permanent storage like Azure Cloud Shell without an attached file share, back up your keys to a safe location
```
標準出力の戻り値にマスタサーバへのsshコマンドがあるので必要ならそれで乗り込むとkubectlがなにもしなくても入っていてクラスタへのクレデンシャルが配置されている。

この時点でダッシュボードからノード数を変えられる

・クラスタに接続するための認証情報を設定ファイルにマージする

```
# az acs kubernetes get-credentials --resource-group $my_resouce_grp --name $my-acs-cluster
Merged "xxxx" as current context in /root/.kube/config
```

・kubectlを入れて使う

centos7ならyumで入るようでした（ACSクラスタはubuntsでできていた）

```
# yum install -y kubectl
```

```
# kubectl get nodes
# kubectl cluster-info
# kubectl get po,deploy,rs,svc,ds --all-namespaces
```
とくに何もしてないとkube-systemというnamespaceの情報がでてくる

### Datadogエージェントを色々な入れ方でいれる

201807現在のdatadog-agentのメジャーバージョンは6になる。  

#### VMの場合   

・パッケージインストール（サインアップ画面で表示されるワンライナー）    

```
DD_API_KEY=a04e9e02f5**************b37bd6a bash -c "$(curl -L https://raw.githubusercontent.com/DataDog/datadog-agent/master/cmd/agent/install_script.sh)"
```

対象：監視が必要なすべてのホストに。   

・設定修正   
   
```
$ cd /etc/datadog-agent/   
$ cp -p datadog.yaml{,.org} 
$ vi datadog.yaml
$ sudo diff datadog.yaml datadog.yaml.org   
256c256
< config_providers:
---
> # config_providers:
260,261c260,261
<   - name: kubelet
<     polling: true
---
> #   - name: kubelet
> #     polling: true
505c505
< process_config:
---
> # process_config:
510c510
<   enabled: "true"
---
> #   enabled: "true"

$ sudo systemctl status datadog-agent
$ sudo systemctl restart datadog-agent
$ sudo systemctl status datadog-agent
```


プロセスが取得できるようにとkubeletのチェックができるように設定を実施。
（コンテナ内のプロセスまで見なくていいらしいけどVMでetcdが動いてるかどうか的なVM上のプロセスは見たい）


#### Azure統合の場合

・DatadogのIntegrationの設定画面で以下を登録する

　サービスプリンシパルのクライアントIDとパスワード、AzureADのディレクトリのテナントのID

https://docs.datadoghq.com/integrations/azure/   
https://docs.datadoghq.com/ja/integrations/azure/  

※ResouceGroup限定できてないせいかサブスクリプションに含まれるホストが丸ごと出てくるという仕様な気がした

#### k8s統合の場合

ACSの環境のマニュアル  
https://docs.microsoft.com/ja-jp/azure/container-service/kubernetes/  
   
AKSのマニュアル   
https://docs.microsoft.com/ja-jp/azure/aks/   
  
k8sクラスタがある前提で話をすすめる。

helmチャートもあるのでそれでもいいかもしれないですがここでは普通にマニフェストで入れます。
公式そのままだとなんかマスタに入らなかったりしたのでtolerationsを追加した。

・まずAPIキーをSecretに登録する   

```
$ echo -n "${DD_API_KEY}"|base64
$ vi secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  apikey: <ここにエンコードしたAPIKEYを記入>

$ kubectl create -f secret.yaml
secret "mysecret" created

$ kubectl get secret
$ kubectl describe secret mysecret
```

・変数をConfigmapに登録する

```
$ vi configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfigmap
  namespace: default
data:
  # キー名が環境変数名として展開される
  KUBERNETES: "yes"
  DD_COLLECT_KUBERNETES_EVENTS: "true"
  DD_LEADER_ELECTION: "true"
  DD_PROCESS_AGENT_ENABLED: "true"
  DD_LOGS_ENABLED: "true"
  DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL: "true"

$ kubectl create -f configmap.yaml 
configmap "myconfigmap" created

$ kubectl get configmap
NAME          DATA      AGE
myconfigmap   1         15m
$ kubectl describe configmap myconfigmap
```


・つぎに登録した値を読み込むdatadogのdaemonsetのマニフェストを用意する    

```
$ vi datadog-agent.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: datadog-agent
spec:
#  updateStrategy:
#    type: RollingUpdate
#    rollingUpdate:
#    maxUnavailable: 1
#    minReadySeconds: 10
  template:   ##Podのテンプレート
    metadata:
      labels:
        app: datadog-agent
      name: datadog-agent
    spec:
      containers:
      - image: datadog/agent:latest
        imagePullPolicy: Always
        name: datadog-agent
        ports:
          - containerPort: 8125
            name: dogstatsdport
            protocol: UDP
          - containerPort: 8126
            name: traceport
            protocol: TCP
        envFrom:                     ##Configmapの変数を一括読み込み
          - configMapRef:
              name: myconfigmap
        env:                         ##環境変数を定義（Secretをここで定義
          - name: DD_API_KEY
            valueFrom:
              secretKeyRef:
                name: mysecret
                key: DD_API_KEY
## 以下があるとホストのhostnameコマンドの出力（本当のホスト名）ではなく、
## K8Sノード名(AWSの場合、ip-<private ip>)が使われてしまって、トレース、メトリクス、
## ログの#hostタグの値の整合がとれなくなってしまう
## https://github.com/DataDog/dd-agent/issues/3496#issuecomment-325642715
#          - name: DD_KUBERNETES_KUBELET_HOST
#            valueFrom:
#              fieldRef:
#                fieldPath: status.hostIP
        resources:
          requests:
            memory: "256Mi"
            cpu: "200m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        volumeMounts:
          - name: dockersocket
            mountPath: /var/run/docker.sock
          - name: procdir
            mountPath: /host/proc
            readOnly: true
          - name: cgroups
            mountPath: /host/sys/fs/cgroup
            readOnly: true
        livenessProbe:
          exec:
            command:
            - ./probe.sh
          initialDelaySeconds: 15
          periodSeconds: 5
      tolerations:                        ##マスタに配置されるように定義
      - key: node-role.kubernetes.io/master
        operator: Equal
        value: "true"
        effect: NoSchedule
      volumes:
        - hostPath:
            path: /var/run/docker.sock
          name: dockersocket
        - hostPath:
            path: /proc
          name: procdir
        - hostPath:
            path: /sys/fs/cgroup
          name: cgroups
```

Daemonsetというのは、Podがホスト毎に1つずつ配置されるリソース。
Taintsがマスタに設定されておりそれに一致したtolerationsの指定をしていないと、
DaemonSetでもPodが配置されない、というスケジュールの仕組みになってるためtolerationsを設定。
（/etc/kubernetes/のしたのほうにあるkube-proxyのマニフェストにあるのと同じtolerations。）

https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
https://qiita.com/sheepland/items/8fedae15e157c102757f    


・daemonsetでdatadogエージェントのPodを配置   

```
$ kubectl create -f datadog-agent.yaml
$ kubectl get ds,po -o wide

NAME               DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE-SELECTOR   AGE       CONTAINER(S)    IMAGE(S)               SELECTOR
ds/datadog-agent   3         3         3         3            3           <none>          1d        datadog-agent   datadog/agent:latest   app=datadog-agent

NAME                     READY     STATUS    RESTARTS   AGE       IP            NODE
po/datadog-agent-08056   1/1       Running   0          1d        10.244.2.10   k8s-agent-91c01bd8-1
po/datadog-agent-pbkcb   1/1       Running   0          1d        10.244.1.9    k8s-agent-91c01bd8-0
po/datadog-agent-w9dmb   1/1       Running   0          1d        10.244.3.6    k8s-master-91c01bd8-0
```
あとたぶんkube-state-metricsとかも入れたほうがいいのであとでたぶんhelmで入れなおす気がします。
Monitor登録とかも一応ためしていていつものVMのリソース・プロセス監視と外形監視とブラウザからポチポチ追加したり通知の文面にホスト変数やイベントIDやテキストなどの変数入れたりできて、
内容をExportしといてjsonにしといてそれをもとに流用してスクリプト組んでAPIで登録するというのもできてた。k8s的にはEventが大事らしいとかテンプレート毎のリソースの割り当てやノード側の制限方法やPod毎のデザインされた数と落ちて大丈夫な数の指定やLivenessProbeなどなどあるようでEvent監視はSyncloopBackoffほか登録したけども次回のcndjpでそのへんわかる気がするしkube-state-metricsいれるとタグでdeployment指定とかできるような記事をどこかでみたような（これからためします）。

### mysqlをVM（Ubuntu）にふつうにシングルで入れる

InnoDBクラスタとかmysql-operatorとかStatefulSetでもよかったけどそちらに夢中になってしまうとアレなのでシンプルに。
（あとで外部サービスとしてのEndpointとServiceオブジェクト作ってアクセスさせる）

yumだとここのあたりだけども
https://dev.mysql.com/doc/mysql-yum-repo-quick-guide/en/   

Ubuntuなのでこのあたりで。（はじめてUbuntuにMySQLをいれた）
https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/en/
https://websiteforstudents.com/install-mysql-8-0-on-ubuntu-16-04-17-10-18-04/   

マスタにわたるためのssh鍵でエージェントにも渡れる。

```
$ tail -3 /etc/hosts
10.240.0.6 k8s-agent-91C01BD8-nic-0 agent0
10.240.0.5 k8s-agent-91C01BD8-nic-1 agent1
10.240.255.5 k8s-master-91C01BD8-nic-0 master1

$ ssh agent0
なんとなくGIP確認
$ curl http://taruo.net/ip/?raw

cd /tmp/ && wget https://dev.mysql.com/get/mysql-apt-config_0.8.10-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.10-1_all.deb
OKおす
sudo apt-get update

sudo apt-get install mysql-server mysql-client

The following additional packages will be installed:
  libaio1 libmecab2 mecab-ipadic mecab-ipadic-utf8 mecab-utils mysql-common
  mysql-community-client mysql-community-client-core mysql-community-server
  mysql-community-server-core
The following NEW packages will be installed:
  libaio1 libmecab2 mecab-ipadic mecab-ipadic-utf8 mecab-utils mysql-client
  mysql-common mysql-community-client mysql-community-client-core
  mysql-community-server mysql-community-server-core mysql-server
0 upgraded, 12 newly installed, 0 to remove and 106 not upgraded.
Need to get 49.2 MB of archives.
After this operation, 403 MB of additional disk space will be used.
Do you want to continue? [Y/n] 

#あと「強烈なパスワードの暗号化を使用する（推奨）」にOKおした（けどあとで設定なおした）
#（5.xと互換性がなくなるやつ）

$ sudo systemctl status mysql
● mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)   Active: active (running) since Fri 2018-07-13 07:27:26 UTC; 2min 15s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
 Main PID: 81202 (mysqld)
   Status: "SERVER_OPERATING"
   CGroup: /system.slice/mysql.service
           └─81202 /usr/sbin/mysqld
```

起動している。   
  
設定ファイル探した感じ以下のあたりにある   

`$ vi /etc/mysql/mysql.conf.d/mysqld.cnf`

これをみたかんじ、上記がサーバ設定で`conf.d/mysql.cnf`がクライアント用です。   
http://jitsu102.hatenablog.com/entry/2018/05/06/191139   

```
$ cat /etc/mysql/mysql.conf.d/mysqld.cnf 
$ mysqld --verbose --help
$ mysqld --verbose --help --no-defaults      

sudo cp -p  /etc/mysql/mysql.conf.d/mysqld.cnf{,.org}
sudo vi  /etc/mysql/mysql.conf.d/mysqld.cnf 
$ sudo diff /etc/mysql/mysql.conf.d/mysqld.cnf{,.org}
34,71d33
< 
< # 旧 MySQL (5.7) との互換性確保
< default_authentication_plugin=mysql_native_password
< 
< explicit_defaults_for_timestamp = true
< 
< sql_mode = 'IGNORE_SPACE,PIPES_AS_CONCAT'
< server-id = 101
< 
< log-bin-trust-function-creators=1
< 
< character-set-server = utf8mb4
< collation-server = utf8mb4_ja_0900_as_cs
< 
< # MySQL5.7の設定の互換性確保
< #character-set-server = utf8
< #collation-server = utf8_general_ci
< #init-connect = SET NAMES utf8
< 
< #lower_case_table_names = 1
< 
< # expire_logs_days = 1   <--- 次回から廃止の可能性あり
< binlog_expire_logs_seconds=18000
< 
< slow_query_log=1
< long_query_time = 1.0
< 
< max_connections = 300
< max_connect_errors = 10
< 
< # transaction_isolation = READ-COMMITTED
< 
< innodb_dedicated_server=ON
< innodb_lock_wait_timeout = 120
< # innodb_flush_log_at_trx_commit=0
< 
< slave-skip-errors=1062,1032
< 

$ sudo systemctl status mysql
$ sudo systemctl restart mysql
$ sudo systemctl status mysql
```

起動した。(parameterは適当です)  

NWを介して接続可能でGrantOptionは持たないユーザを作成する
(phpmyadmin越しにユーザ作成は不可能になる）
GRANTのみによるユーザ作成はできなかったと思われる。

```
mysql -u root -p
CREATE USER user@'%' IDENTIFIED BY 'xxxxxx';
GRANT ALL ON *.* TO 'user'@'%';
show grants for user@'%';
FLUSH PRIVILEGES;
exit
```
この接続情報をphpmyadminでつかう。

### phpmyadminをマニフェストでいれてみる

・secretにMySQLのパスワードを登録する   

```
$ echo -n "axxxxxxx"|base64
YX*****aGc=
$ vi secret.yaml 
$ cat secret.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  MYSQL_PASSWORD: YXY1****aGc=

$ kubectl apply -f secret.yaml 
```

・configmapにMySQLのパスワード以外の接続情報を登録する   

```
$ vi configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfigmap
  namespace: default
data:
  # キー名が環境変数名として展開される
  PMA_HOST: "external-ip-database.default.svc.cluster.local"
  PMA_USER: user
  PMA_PORTS: "3306"
  PMA_ARBITRARY: "1"
  PMA_VERBOSE: phpmyadmin

$ kubectl apply -f configmap.yaml
```
どんな変数が必要かはコンテナイメージのあるdocker_hubの解説を確認します。
https://hub.docker.com/r/phpmyadmin/phpmyadmin/
PMA_HOSTは次のyamlで作るDBのEndpointのServiceの名前。
service-name.namespace-name.svc.cluster.localが名前解決できてホストの指定に使える。   

・本体のマニフェストを作成（Service、Deployment、Endpointを作成）

```
$ vi phpmyadmin.yaml 
---
apiVersion: v1
kind: Service
metadata:
  name: external-ip-database
spec:
  ports:
  - protocol: TCP
    port: 3306
    targetPort: 3306
---
apiVersion: v1
kind: Endpoints
apiVersion: v1
metadata:
  name: external-ip-database
subsets:
  - addresses:
    - ip: 10.240.0.6
    ports:
    - port: 3306
---
apiVersion: v1
kind: Service
metadata:
  name: phpmyadmin-front
spec:
  type: LoadBalancer
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: phpmyadmin
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: phpmyadmin
  namespace: default
spec:
  replicas: 1
  template:
    metadata:
      labels:
        run: phpmyadmin
    spec:
      containers:
      - name:  phpmyadmin
        image: phpmyadmin/phpmyadmin
        imagePullPolicy: Always
        ports:
        - containerPort: 80
        ## load PMA_HOST,PMA_USER,PMA_PORTS,PMA_ARBITRARY,PMA_VERBOSE
        envFrom:
          - configMapRef:
              name: myconfigmap
        env:
        - name:  PMA_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysecret
              key:  MYSQL_PASSWORD

$ kubectl apply -f phpmyadmin.yaml

```
それぞれのリソースが疎結合(パーツ交換しやすい)だけど名前とlabelとセレクタなどでうっすら関係があるようになっているというかんじらしい。
phpmyadmin-frontend(Service) -> phpmyadmin(deployment) -> external-ip-database(Service) -> Endpoint(DBのIPアドレスを名前解決) -> vmに入れたmysql

https://qiita.com/MahoTakara/items/d18d8f9b36416353066c

yamlをapplyしたらそれぞれの状況を確認、
とくにLoadBalancerを指定したフロントのServiceに割り当たるExternalIPを確認して
それをブラウザで開いてphpmydaminの表示を確認する。   

```
$ kubectl get po,svc,deploy,rc,ep,ds,cm,secret -o wide
NAME                             READY     STATUS    RESTARTS   AGE       IP            NODE
po/datadog-agent-08056           1/1       Running   0          6d        10.244.2.10   k8s-agent-91c01bd8-1
po/datadog-agent-pbkcb           1/1       Running   0          6d        10.244.1.9    k8s-agent-91c01bd8-0
po/datadog-agent-w9dmb           1/1       Running   0          6d        10.244.3.6    k8s-master-91c01bd8-0
po/phpmyadmin-4033992027-b857p   1/1       Running   0          33m       10.244.2.16   k8s-agent-91c01bd8-1

NAME                       CLUSTER-IP    EXTERNAL-IP      PORT(S)        AGE       SELECTOR
svc/external-ip-database   10.0.187.44   <none>           3306/TCP       1h        <none>
svc/kubernetes             10.0.0.1      <none>           443/TCP        11d       <none>
svc/phpmyadmin-front       10.0.54.158   40.xxx.xxx.xxx   80:31464/TCP   4h        app=phpmyadmin,run=phpmyadmin

NAME                DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINER(S)   IMAGE(S)                SELECTOR
deploy/phpmyadmin   1         1         1            1           3h        phpmyadmin     phpmyadmin/phpmyadmin   run=phpmyadmin

NAME                      ENDPOINTS           AGE
ep/external-ip-database   10.240.0.6:3306     4h
ep/kubernetes             10.240.255.15:443   11d
ep/phpmyadmin-front       10.244.2.16:80      4h

NAME               DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE-SELECTOR   AGE       CONTAINER(S)    IMAGE(S)               SELECTOR
ds/datadog-agent   3         3         3         3            3           <none>          6d        datadog-agent   datadog/agent:latest   app=datadog-agent

NAME                         DATA      AGE
cm/datadog-leader-election   0         6d
cm/myconfigmap               11        7d

NAME                          TYPE                                  DATA      AGE
secrets/default-token-twh7p   kubernetes.io/service-account-token   3         11d
secrets/mysecret              Opaque                                2         7d
```

httpsと認証は別途という感じに。
Azureなのでアプリケーションゲートウェイを手前にかますことは可能な模様でした（LoadbalancerのIP指定して）
helmもあるようだったのでそちらの方が簡単かも（今回は意味と操作を理解するためにあえて書いた）
[helmで仕組みが隠蔽されちゃうと理解しづらいし書いた人の一存で使いやすさが分かれるのでkustomizeがいいよみたいな話をみた](https://www.youtube.com/watch?v=Tnp5Ly0VHOk)気がします。（たぶんチャート書くレベルの人の話）


・podに入る方法と環境変数の確認方法と名前解決の確認方法

```
$ kubectl exec -it phpmyadmin-2566823841-7gwjd /bin/sh

# nslookup external-ip-database.default.svc.cluster.local
Name:      external-ip-database.default.svc.cluster.local
Address 1: 10.0.187.44 external-ip-database.default.svc.cluster.local

# env
PHP_EXTRA_CONFIGURE_ARGS=--enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data --disable-cgi
EXTERNAL_IP_DATABASE_SERVICE_PORT=3306
PHPMYADMIN_FRONT_PORT_80_TCP=tcp://10.0.54.158:80
KUBERNETES_PORT=tcp://10.0.0.1:443
KUBERNETES_SERVICE_PORT=443
EXTERNAL_IP_DATABASE_PORT=tcp://10.0.187.44:3306
PMA_PASSWORD=xxxxxxx
EXTERNAL_IP_DATABASE_PORT_3306_TCP=tcp://10.0.187.44:3306
URL=https://files.phpmyadmin.net/phpMyAdmin/4.8.2/phpMyAdmin-4.8.2-all-languages.tar.xz
PHP_INI_DIR=/usr/local/etc/php
～略～
```
コンテナはサイズ小さくしたい関係でコマンドが限られたものしか入ってないことが多くbashないことも。
あと、マニフェストのapiVersionとkubernetesのバージョンで許容する書き方が案外違っている感じだった。

いちおう、マイクロサービスの集合を扱うようなのが向いててそうでもない規模の場合にマスタと移行と学習のコストがという話は理解していて、ただマスタは無料みたいなPaaSが多いのと、イメージによる管理ができることで環境差分の管理が簡単になってテストをポータブルに簡単にできてVMかまさないから起動早いところがいいとかそういうことかなというところ。オートスケーリングとオートヒーリングを使いこなすとありがたみがわかりやすそう。あとステートフルなのは全然向いてなくてAPIの集合みたいなステートレスなシステム(PaaSみたいなのかな)が向いてるらしい。（コンテナで本番DB運用してる人をみない。PaaSのDBつかってる。）

https://qiita.com/komattaka/items/bd1d8d32f6cb24a32f53
https://qiita.com/MahoTakara/items/d18d8f9b36416353066c
https://qiita.com/MahoTakara/items/098a794c71f0ae2be429
https://hub.docker.com/r/phpmyadmin/phpmyadmin/
https://github.com/phpmyadmin/docker
https://github.com/kubernetes/charts/tree/master/stable/datadog
https://www.datadoghq.com/ja/blog/monitoring-kubernetes-datadog/#kubernetes-components
https://qiita.com/mumoshu/items/4c19695e5c9e3edd098b
https://thinkit.co.jp/article/13542
http://dr-asa.hatenablog.com/entry/2018/04/10/171807
https://knowledge.sakura.ad.jp/3681/
https://docs.microsoft.com/ja-jp/azure/aks/
https://qiita.com/superbrothers/items/650d6591aa6531bdbd08
https://qiita.com/cvusk/items/100dfb955150ef8964e5
https://codezine.jp/article/detail/10828
https://access.redhat.com/obsolete-documentation/ja/red-hat-enterprise-linux-atomic-host/7/paged/getting-started-with-containers/chapter-4-troubleshooting-kubernetes
https://github.com/oracle/mysql-operator/blob/master/docs/tutorial.md
http://dr-asa.hatenablog.com/entry/2017/12/19/095008
https://github.com/yoshioterada/k8s-Azure-Container-Service-AKS--on-Azure
https://kubernetes.io/docs/concepts/storage/persistent-volumes/