Alibaba Container Service for Kubernetesでアプリを公開する。

# はじめに
AWSのEKSやGCPのGKEなどにアプリケーションをデプロイする方法についての記事は数多く見かけるのに、AlibabaCloudのACKに関する記事が少ないように感じたので、本記事で紹介しようと思いました。ACKを触り始めてとりあえずデプロイの方法を知りたいという方に読んでいただければと思います。

# 今回やること
NginxのWebサーバをACK上に構築し、外部公開することを目標とします。
環境のイメージはこんな感じ。
![k8s_HandsOn_Architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667295/7bcc5bcf-46e4-0842-5111-fcff4e82b45d.png)
ワークサーバはACKにアクセスするための作業場所になるので、ご自身のローカル端末で問題ありせん。
ACK上にns-demoネームスペースを作成し、リソースを作成していきます。サービスの公開はLoadBalancerタイプのServiecで行います。Alibaba CloudではLBタイプのServiceを作成した時点で自動的にSLB（現CLB）を自動的に作成してくれるので楽ちんですね。


# 手順
## Dockerイメージの作成（ビルド） + ACRへプッシュ
### 1. Dockerfile作成
今回作成するDockerfileは必要最低限のもの。
srcにはindex.htmlとCSSを配置しています。ここはお好みで。ディレクトリ構成は以下。
```shell
.
├── Dockerfile
├── READM.md
├── img
│   └── k8s_HandsOn_Architecture.png
├── manifests
│   ├── deployment.yaml
│   ├── secret.yaml
│   └── service.yaml
└── src
    ├── index.html
    └── style.css
```
```Dockerfile
FROM 'nginx:latest'

COPY ./src /usr/share/nginx/html

CMD service nginx start
```

### 2. ACRログイン
ACR(Alibaba Container Registry)にイメージをPushしてから利用するため、まずログインします。
コマンド実行するとパスワードを要求されるため、[事前にパスワードを作成](https://qiita.com/AstroPman/items/0b4ad2d6e5c9163d6f10)しておく必要があります。

```shell
docker login --username=<username> <acr_instance_endpoint>
```
### 3. Docker Build + Push
アプリを作成し、Dockerfileまで作成したら以下のコマンドでImageの作成（ビルド）とACRへのアップロード（プッシュ）を行います。
```bash
docker build <path> -t <acr_instance_endpoint>/<namespace>/<repositry_name>:<tag>
docker push <acr_instance_endpoint>/<namespace>/<repositry_name>:<tag>
```

### 4. ACKクラスターへ接続
接続 = kubectlでクラスター操作ができるようになることです。
kubectlはデフォルトで`$HOME/.kube/config`を確認する。（tips: 環境変数`$KUBECONFIG`を変更することで任意のファイルを参照することも可能）
ACKクラスター情報より接続情報を取得し、configに記載する。
準備ができたら以下のコマンドを実行し、ノードが表示されれば接続完了。
```
# kubeconfig例
apiVersion: v1
clusters:
- cluster:
    server: https://10.2.2.143:6443
    certificate-authority-data: 
    ...
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: "xxxxxxxxxxxx"
  name: 288171762353309774-c3ce92774b1f34cc78871b1eef56ed097
current-context: 288171762353309774-c3ce92774b1f34cc78871b1eef56ed097
kind: Config
preferences: {}
users:
- name: "xxxxxxxxxxxx"
  user:
    ...
```
```shell
# 確認コマンド   
kubectl get node
```

### 5. マニフェスト作成とデプロイ
アプリに必要なオブジェクトのマニフェストを作成する。
```yaml:deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
  namespace: ns-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: demo-app
  template:
    metadata:
      labels:
        app: demo-app
    spec:
      containers:
      - name: nginx
        image: <pushしたImage名>:<tag>
        imagePullPolicy: Always  # Podが作成される時必ずCRからImageをPullする。
      imagePullSecrets:
      - name: acr-key  # ImageをPullために必要な認証情報
```
```yaml:service.yaml
apiVersion: v1
kind: Service
metadata:
  name: demo-app-svc
  namespace: ns-demo
spec:
  type: LoadBalancer  # SLBが自動的に作成される。
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: demo-app  # このラベルがついているPodに処理を割り振る。
```
secret.yamlにはImagePullSecretとして登録する認証情報を登録する。
```yaml:secret.yaml
apiVersion: v1
metadata:
  name: acr-key
  namespace: ns-demo 
data:
  .dockerconfigjson: ....
type: kubernetes.io/dockerconfigjson
```

```bash
# Namespace作成
kubectl create ns ns-demo
# オブジェクトをデプロイ
kubectl apply -f manifest/ -R
```

### 6. 確認
以下のコマンドでデプロイしたオブジェクトたちを確認する。
```bash
# kubectl get deploy,po,svc,secret -n ns-demo
```
Serviceに紐づくSLBが自動的に作成されていることも確認する。
SLBが作成されていれば、Serviceに付与されるExternalIPでアプリにアクセスできるはず。
`http://<ExternalIP>/`をブラウザに入力してひらけば見えるはず。


### 7. 環境の削除
```bash
# オブジェクトの削除
kubectl delete -f manifest/ -R
# 確認
kubectl get deploy,po,svc,secret -n ns-demo
# Namespaceの削除
kubectl delete ns ns-demo
# 確認
kubectl get ns
```

# あとがき
書いてみて思いましたが、ACK特有の操作はほとんどなかったですね。笑
Alibaba Cloud使ってみようとしている方の参考になれば幸いです。