k8s環境ハンズオン webアプリケーション構築実践編

# k8s環境ハンズオン webアプリケーション構築実践編

本セクションではminikubeの中に三層アプリを構築してきます。

- デバッグ用イメージ作成
- DBサーバーのイメージ作成
- DBサーバーの構築（ストレージ）
- DBサーバーの構築（Pod）
- DBサーバーの構築（Pod+Secret）
- DBサーバーの構築（StatefulSet）
- DBサーバーの構築（HeadlessService）
- DBサーバーの構築（初期化）
- APサーバーのイメージ作成
- APサーバーの構築（Pod+Secret）
- APサーバーの構築（Deployment）
- APサーバーの構築（Service）
- WEBサーバーのイメージ作成
- WEBサーバーの構築（Pod）
- WEBサーバーの構築（Pod+ConfigMap）
- WEBサーバーの構築（Deployment）
- WEBサーバーの構築（Service）
- Webアプリケーションの公開（Ingress）




-----------------------------------------------------------------------------------------------
## 作成するアプリ

minikubeの中に三層アプリを構築

web→ap→db→localstorage


-----------------------------------------------------------------------------------------------

## デバッグ用イメージ作成


実装
1. 以下の3ファイルを作成
      mongodb-org-4.0.repo
      Dockerfile
      debug-pod.yml


確認
  Docker
    1. Dockerで作成したイメージを実行
    2. 実行中コンテナに入る
    3. 必要なコマンドが実行可能なことを確認

  Kubernetes
    1. Podを作成
    
    


```mongodb-org-4.0.repo
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
```



```Dockerfile
FROM centos:7

COPY . /tmp/debug

RUN  \
# Install MongoDB shell, tools.
mv /tmp/debug/mongodb-org-4.0.repo /etc/yum.repos.d; \
yum install -y mongodb-org-shell-4.0.5 mongodb-org-tools-4.0.5; \
# Install ip , ifconfig command.
yum install -y iproute net-tools; \
# Install jq
curl -o /usr/local/bin/jq -L https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64; \
chmod +x /usr/local/bin/jq; \
# Delete cache files.
yum clean all;
```



```yml:debug-pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: debug
  namespace: default
spec:
  containers:
    - name: debug
      image: debug
      imagePullPolicy: Never
      command:
        - "sh"
        - "-c"
      args:
        - |
          while true
          do
            sleep 5
          done
```


上記３ファイルをvmにうつし、ビルドコマンド実行
(dockerfileにビルド申請を投げかける)

```
docker build -t debug .
```

debugイメージの確認

```
docker image ls
```

debugイメージを実行する

```
docker run -it debug sh
```

入り込んだコンテナで下記のコマンドでipを確認

```
ip;mongo;ifconfig;
```

mongodbが正しく動いている確認したら
コンテナを削除する。

```
docker container prune
```

続いてk8sで動作させるマニフェストファイルapplyする

```
kubectl apply -f debug-pod.yml
#動作確認
kubectl get pod
```

中に入って動作確認する

```
kubectl exec -it debug sh
```


```
ip;mongo;ifconfig;

exit;
```

```
#動作確認
kubectl get pod
```

-----------------------------------------------------------------------------------------------
## DBサーバーのイメージ作成


実装
1. 以下の3ファイルを作成
      .dockerignore
      docker-entrypoint.sh
      Dockerfile


確認
1. Dockerで作成したイメージを実行
2. 実行中コンテナに入る
3. MongoDBに接続できることを確認



```.dockerignore
**/.git
**/.DS_Store
**/node_modules
```


```
#! /bin/sh
INIT_FLAG_FILE=/data/db/init-completed
INIT_LOG_FILE=/data/db/init-mongod.log

start_mongod_as_daemon() {
echo 
echo "> start mongod ..."
echo 
mongod \
  --fork \
  --logpath ${INIT_LOG_FILE} \
  --quiet \
  --bind_ip 127.0.0.1 \
  --smallfiles;
}

create_user() {
echo
echo "> create user ..."
echo
if [ ! "$MONGO_INITDB_ROOT_USERNAME" ] || [ ! "$MONGO_INITDB_ROOT_PASSWORD" ]; then
  return
fi
mongo "${MONGO_INITDB_DATABASE}" <<-EOS
  db.createUser({
    user: "${MONGO_INITDB_ROOT_USERNAME}",
    pwd: "${MONGO_INITDB_ROOT_PASSWORD}",
    roles: [{ role: "root", db: "${MONGO_INITDB_DATABASE:-admin}"}]
  })
EOS
}

create_initialize_flag() {
echo
echo "> create initialize flag file ..."
echo
cat <<-EOF > "${INIT_FLAG_FILE}"
[$(date +%Y-%m-%dT%H:%M:%S.%3N)] Initialize scripts if finigshed.
EOF
}

stop_mongod() {
echo
echo "> stop mongod ..."
echo
mongod --shutdown
}

if [ ! -e ${INIT_LOG_FILE} ]; then
  echo 
  echo "--- Initialize MongoDB ---"
  echo 
  start_mongod_as_daemon
  create_user
  create_initialize_flag
  stop_mongod
fi

exec "$@"
```



```Dockerfile
FROM alpine:3.9

COPY docker-entrypoint.sh /usr/local/bin

RUN \
adduser -g mongodb -DH -u 1000 mongodb; \
apk --no-cache add mongodb=4.0.5-r0; \
chmod +x /usr/local/bin/docker-entrypoint.sh; \
mkdir -p /data/db; \
chown -R mongodb:mongodb /data/db;

VOLUME /data/db

EXPOSE 27017

ENTRYPOINT [ "docker-entrypoint.sh" ]
CMD [ "mongod" ]
```



セットしたdockerfileをビルドする。

```
docker build -t weblog-db:v1.0.0 .
```

dockerをデーモン起動する。

```
docker run -d weblog-db:v1.0.0
```

起動しているかコンテナ一覧確認

```
[root@localhost ~]# docker container ls
CONTAINER ID        IMAGE                           COMMAND                   CREATED              STATUS              PORTS               NAMES
46aa0fa9b017        2d3813851e87                    "kube-scheduler --bi…"    About a minute ago   Up About a minute                       k8s_kube-scheduler_kube-scheduler-minikube_kube-system_31d9ee8b7fb12e797dc981a8686f6b2b_6
88649a10f187        weblog-db:v1.0.0                "docker-entrypoint.s…"    3 minutes ago        Up 3 minutes        27017/tcp           gifted_spence
```

コンテナの中に入ってmongodbが動作しているか確認

```
docker exec -it gifted_spence sh
```

mongodbが正しく動いている確認

```
show dbs
```

dockerコンテナ停止して削除

```
[root@localhost ~]# docker stop gifted_spence
gifted_spence
[root@localhost ~]# docker system prune
```




-----------------------------------------------------------------------------------------------
## DBサーバーの構築（ストレージ）


実装
1. 以下のファイルを作成
    weblog-db-storage.yml


確認
※必要なフォルダが作成されていること

1. PersistentVolume、PersistentVolumeClaimを作成
2. 作成したリソースを確認


```weblog-db-storage.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/storage"
    type: Directory

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: storage-claim
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
```





-----------------------------------------------------------------------------------------------
## DBサーバーの構築（Pod）


実装
1. 以下のファイルを作成
    weblog-db-pod.yml


確認
※必要なフォルダが作成されていること
※作成されたフォルダは空であること

1. PersistentVolume, PersistentVolumeClaim, Podを作成
2. MongoDBのファイルが作成されていることを確認
3. 作成したPodへ入る
4. MongoDBへ接続確認




```weblog-db-pod.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/storage"
    type: Directory

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: storage-claim
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

---
apiVersion: v1
kind: Pod
metadata:
  name: mongodb
  namespace: default
  labels:
    app: weblog
    type: database
spec:
  containers:
  - name: mongodb
    image: weblog-db:v1.0.0
    imagePullPolicy: Never
    command:
    - "mongod"
    - "--bind_ip_all"
    volumeMounts:
    - mountPath: /data/db
      name: storage
  volumes:
  - name: storage
    persistentVolumeClaim:
      claimName: storage-claim
```



-----------------------------------------------------------------------------------------------
## DBサーバーの構築（Pod+Secret）


実装
1. keyfile（ランダム文字列）を作成
2. Secretリソースを作成
3. SecretリソースのYAMLを取得
4. weblog-db-pod.ymlへマージ
5. Secretリソースを削除


確認
※必要なフォルダが作成されていること
※作成されたフォルダは空であること

1. PersistentVolume, Pod, Secretを作成
2. 作成したPodへ入る
3. MongoDBへ接続
4. 設定したユーザー名/パスワードで認証
5. DB一覧を表示



```keyfile
DFCytNO0mwawyBs25EOwptvC1TicPzI39KkojjhfE7HeR/VvryeNwqdOvOwiZ9jP/pIWIeYUYiktZXfXhOOlyMBEwUCGr+umbmEeududNy4hQCsVe0YOSlX07Xqa//o+mz4Z8pEchN0wUahqpHD5ieFyoMNIVaEcFPF43+3vZovw7M4xaY+xhhnW5etgm/c2g9GaGlJ4aXPXJbHQTylscnivBrmWiIY+JAPc+oFGJL5I3OCiSR1d66gG99ysof76Rtx0MvYgWdX9rSe16odaI3IWtmhI2CLbWpS994nYcWTCbtor3fMC1cs8nNRWy1un+JbbPooMqiRObxRncHap2X+pOKtjYPg+YKX1Htf+XyaH7DrFdZMnsVbAtAgV6Cf67IZym65p8LjjFkhZTbn5ZMgjQinwerkB+QC5hmaQQhAu6z5te+kPrsQg4PQ/JCRL7vweZEzddwlCo8NYGUJXaSG0Lg2k7wDx9oHLTuA/Telit2VrfgRbU6Y6f6FEOczjKnHKgHT09RJa56wdihgHreyWbVCC7BfdFJ2zRj1fG5YEgpkA3pgMsuvUDi6Ai6tNVe3O3jAqCmXghpFbryi9XYgtDsQkpGPRUZyLvNBj5k8qBoiYkiHPWvyIbyB9SX0pcyP10R8zR0TB8pXUZb3Xh1p4VDMTtg5u8Wwf56pIrWe3KYj20P2wWyQ3glDo5GMJxUdoubTxOun2+V0J6Oc0dKlmweqEjAbakJiDdyvty2OggnbgRSNYZInNKVR9nbnPUE/kCSMbNeE5hVVFC0zx6FKHkdxiZFEv8bP/LR4hY49OEZa9vuPRBn2LqflucO7wm5OnD8mN3PY8LlpN6SWCUTGJ2qfwm36vjRKpHxnFH6IcyDVwmbPulCMEnfnL5rKJ/4bZGiE1SQobQGYD/Gbq1UFWok0FMfTFV1wetQfVv32SISJ6PUJM2iThBJWDPNVTmKf28Dlq2NaLFMd1ugKxAWP2fN9YOgw6ZuiiRB/6UbIM7Ms2FWfytGp2oYcy94XP
```



```weblog-db-pod+secret.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/storage"
    type: Directory

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: storage-claim
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

---
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
  namespace: default
  labels:
    app: weblog
    type: database
type: Opaque
data:
  root_username: YWRtaW4=
  root_password: UGFzc3cwcmQ=
  keyfile: REZDeXROTzBtd2F3eUJzMjVFT3dwdHZDMVRpY1B6STM5S2tvampoZkU3SGVSL1Z2cnllTndxZE92T3dpWjlqUC9wSVdJZVlVWWlrdFpYZlhoT09seU1CRXdVQ0dyK3VtYm1FZXVkdWROeTRoUUNzVmUwWU9TbFgwN1hxYS8vbyttejRaOHBFY2hOMHdVYWhxcEhENWllRnlvTU5JVmFFY0ZQRjQzKzN2Wm92dzdNNHhhWSt4aGhuVzVldGdtL2MyZzlHYUdsSjRhWFBYSmJIUVR5bHNjbml2QnJtV2lJWStKQVBjK29GR0pMNUkzT0NpU1IxZDY2Z0c5OXlzb2Y3NlJ0eDBNdllnV2RYOXJTZTE2b2RhSTNJV3RtaEkyQ0xiV3BTOTk0blljV1RDYnRvcjNmTUMxY3M4bk5SV3kxdW4rSmJiUG9vTXFpUk9ieFJuY0hhcDJYK3BPS3RqWVBnK1lLWDFIdGYrWHlhSDdEckZkWk1uc1ZiQXRBZ1Y2Q2Y2N0laeW02NXA4TGpqRmtoWlRibjVaTWdqUWlud2Vya0IrUUM1aG1hUVFoQXU2ejV0ZStrUHJzUWc0UFEvSkNSTDd2d2VaRXpkZHdsQ284TllHVUpYYVNHMExnMms3d0R4OW9ITFR1QS9UZWxpdDJWcmZnUmJVNlk2ZjZGRU9jempLbkhLZ0hUMDlSSmE1NndkaWhnSHJleVdiVkNDN0JmZEZKMnpSajFmRzVZRWdwa0EzcGdNc3V2VURpNkFpNnROVmUzTzNqQXFDbVhnaHBGYnJ5aTlYWWd0RHNRa3BHUFJVWnlMdk5CajVrOHFCb2lZa2lIUFd2eUlieUI5U1gwcGN5UDEwUjh6UjBUQjhwWFVaYjNYaDFwNFZETVR0ZzV1OFd3ZjU2cElyV2UzS1lqMjBQMndXeVEzZ2xEbzVHTUp4VWRvdWJUeE91bjIrVjBKNk9jMGRLbG13ZXFFakFiYWtKaURkeXZ0eTJPZ2duYmdSU05ZWkluTktWUjluYm5QVUUva0NTTWJOZUU1aFZWRkMweng2RktIa2R4aVpGRXY4YlAvTFI0aFk0OU9FWmE5dnVQUkJuMkxxZmx1Y083d201T25EOG1OM1BZOExscE42U1dDVVRHSjJxZndtMzZ2alJLcEh4bkZINkljeURWd21iUHVsQ01FbmZuTDVyS0ovNGJaR2lFMVNRb2JRR1lEL0dicTFVRldvazBGTWZURlYxd2V0UWZWdjMyU0lTSjZQVUpNMmlUaEJKV0RQTlZUbUtmMjhEbHEyTmFMRk1kMXVnS3hBV1AyZk45WU9ndzZadWlpUkIvNlViSU03TXMyRldmeXRHcDJvWWN5OTRYUAo=

---
apiVersion: v1
kind: Pod
metadata:
  name: mongodb
  namespace: default
  labels:
    app: weblog
    type: database
spec:
  containers:
  - name: mongodb
    image: weblog-db:v1.0.0
    imagePullPolicy: Never
    args:
    - "mongod"
    - "--auth"
    - "--bind_ip_all"
    env:
    - name: "MONGO_INITDB_ROOT_USERNAME"
      valueFrom:
        secretKeyRef:
          name: mongo-secret
          key: root_username
    - name: "MONGO_INITDB_ROOT_PASSWORD"
      valueFrom:
        secretKeyRef:
          name: mongo-secret
          key: root_password
    - name: "MONGO_INITDB_DATABASE"
      value: "admin"
    volumeMounts:
    - mountPath: /data/db
      name: storage
    - mountPath: /home/mongodb
      name: secret
  volumes:
  - name: storage
    persistentVolumeClaim:
      claimName: storage-claim
  - name: secret
    secret:
      secretName: mongo-secret
      items:
      - key: keyfile
        path: keyfile
        mode: 0700
```





-----------------------------------------------------------------------------------------------
## DBサーバーの構築（StatefulSet）


実装
1. 以下のファイルを作成
    weblog-db-statefulset.yml


確認
※必要なフォルダが作成されていること
※作成されたフォルダは空であること

1. PersistentVolume, Secret, StatefulSetを作成
2. 作成したPodへ入る
3. MongoDBへ接続
4. 設定したユーザー名/パスワードで認証
5. DB一覧を表示



```weblog-db-statefulset.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume-0
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/pv0000"
    type: Directory

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume-1
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/pv0001"
    type: Directory

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume-2
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/pv0002"
    type: Directory

---
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
  namespace: default
  labels:
    app: weblog
    type: database
type: Opaque
data:
  root_username: YWRtaW4=
  root_password: UGFzc3cwcmQ=
  keyfile: REZDeXROTzBtd2F3eUJzMjVFT3dwdHZDMVRpY1B6STM5S2tvampoZkU3SGVSL1Z2cnllTndxZE92T3dpWjlqUC9wSVdJZVlVWWlrdFpYZlhoT09seU1CRXdVQ0dyK3VtYm1FZXVkdWROeTRoUUNzVmUwWU9TbFgwN1hxYS8vbyttejRaOHBFY2hOMHdVYWhxcEhENWllRnlvTU5JVmFFY0ZQRjQzKzN2Wm92dzdNNHhhWSt4aGhuVzVldGdtL2MyZzlHYUdsSjRhWFBYSmJIUVR5bHNjbml2QnJtV2lJWStKQVBjK29GR0pMNUkzT0NpU1IxZDY2Z0c5OXlzb2Y3NlJ0eDBNdllnV2RYOXJTZTE2b2RhSTNJV3RtaEkyQ0xiV3BTOTk0blljV1RDYnRvcjNmTUMxY3M4bk5SV3kxdW4rSmJiUG9vTXFpUk9ieFJuY0hhcDJYK3BPS3RqWVBnK1lLWDFIdGYrWHlhSDdEckZkWk1uc1ZiQXRBZ1Y2Q2Y2N0laeW02NXA4TGpqRmtoWlRibjVaTWdqUWlud2Vya0IrUUM1aG1hUVFoQXU2ejV0ZStrUHJzUWc0UFEvSkNSTDd2d2VaRXpkZHdsQ284TllHVUpYYVNHMExnMms3d0R4OW9ITFR1QS9UZWxpdDJWcmZnUmJVNlk2ZjZGRU9jempLbkhLZ0hUMDlSSmE1NndkaWhnSHJleVdiVkNDN0JmZEZKMnpSajFmRzVZRWdwa0EzcGdNc3V2VURpNkFpNnROVmUzTzNqQXFDbVhnaHBGYnJ5aTlYWWd0RHNRa3BHUFJVWnlMdk5CajVrOHFCb2lZa2lIUFd2eUlieUI5U1gwcGN5UDEwUjh6UjBUQjhwWFVaYjNYaDFwNFZETVR0ZzV1OFd3ZjU2cElyV2UzS1lqMjBQMndXeVEzZ2xEbzVHTUp4VWRvdWJUeE91bjIrVjBKNk9jMGRLbG13ZXFFakFiYWtKaURkeXZ0eTJPZ2duYmdSU05ZWkluTktWUjluYm5QVUUva0NTTWJOZUU1aFZWRkMweng2RktIa2R4aVpGRXY4YlAvTFI0aFk0OU9FWmE5dnVQUkJuMkxxZmx1Y083d201T25EOG1OM1BZOExscE42U1dDVVRHSjJxZndtMzZ2alJLcEh4bkZINkljeURWd21iUHVsQ01FbmZuTDVyS0ovNGJaR2lFMVNRb2JRR1lEL0dicTFVRldvazBGTWZURlYxd2V0UWZWdjMyU0lTSjZQVUpNMmlUaEJKV0RQTlZUbUtmMjhEbHEyTmFMRk1kMXVnS3hBV1AyZk45WU9ndzZadWlpUkIvNlViSU03TXMyRldmeXRHcDJvWWN5OTRYUAo=

---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
  namespace: default
  labels:
    app: weblog
    type: database
spec:
  selector:
    matchLabels:
      app: weblog
      type: database
  serviceName: db-svc
  replicas: 3
  template:
    metadata:
      name: mongodb
      namespace: default
      labels:
        app: weblog
        type: database
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: mongodb
        image: weblog-db:v1.0.0
        imagePullPolicy: Never
        args:
        - "mongod"
        - "--auth"
        - "--clusterAuthMode=keyFile"
        - "--keyFile=/home/mongodb/keyfile"
        - "--replSet=rs0"
        - "--bind_ip_all"
        env:
        - name: "MONGO_INITDB_ROOT_USERNAME"
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: root_username
        - name: "MONGO_INITDB_ROOT_PASSWORD"
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: root_password
        - name: "MONGO_INITDB_DATABASE"
          value: "admin"
        volumeMounts:
        - mountPath: /data/db
          name: storage
        - mountPath: /home/mongodb
          name: secret
      volumes:
      - name: secret
        secret:
          secretName: mongo-secret
          items:
          - key: keyfile
            path: keyfile
            mode: 0700
  volumeClaimTemplates:
  - metadata:
      name: storage
    spec:
      storageClassName: slow
      accessModes:
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
```


-----------------------------------------------------------------------------------------------
## DBサーバーの構築（HeadlessService）



実装
1. 以下のファイルを作成
    weblog-db-fullset.yml


確認
※必要なフォルダが作成されていること
※作成されたフォルダは空であること

1. PersistentVolume, Secret, StatefulSet, Serviceを作成
2. 作成したPodへ入る
3. MongoDBを初期化
4. レプリカセット構築できていることを確認



```weblog-db-fullset.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume-0
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/pv0000"
    type: Directory

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume-1
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/pv0001"
    type: Directory

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: storage-volume-2
  namespace: default
  labels:
    app: weblog
    type: storage
spec:
  storageClassName: slow
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  hostPath:
    path: "/data/pv0002"
    type: Directory

---
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
  namespace: default
  labels:
    app: weblog
    type: database
type: Opaque
data:
  root_username: YWRtaW4=
  root_password: UGFzc3cwcmQ=
  keyfile: REZDeXROTzBtd2F3eUJzMjVFT3dwdHZDMVRpY1B6STM5S2tvampoZkU3SGVSL1Z2cnllTndxZE92T3dpWjlqUC9wSVdJZVlVWWlrdFpYZlhoT09seU1CRXdVQ0dyK3VtYm1FZXVkdWROeTRoUUNzVmUwWU9TbFgwN1hxYS8vbyttejRaOHBFY2hOMHdVYWhxcEhENWllRnlvTU5JVmFFY0ZQRjQzKzN2Wm92dzdNNHhhWSt4aGhuVzVldGdtL2MyZzlHYUdsSjRhWFBYSmJIUVR5bHNjbml2QnJtV2lJWStKQVBjK29GR0pMNUkzT0NpU1IxZDY2Z0c5OXlzb2Y3NlJ0eDBNdllnV2RYOXJTZTE2b2RhSTNJV3RtaEkyQ0xiV3BTOTk0blljV1RDYnRvcjNmTUMxY3M4bk5SV3kxdW4rSmJiUG9vTXFpUk9ieFJuY0hhcDJYK3BPS3RqWVBnK1lLWDFIdGYrWHlhSDdEckZkWk1uc1ZiQXRBZ1Y2Q2Y2N0laeW02NXA4TGpqRmtoWlRibjVaTWdqUWlud2Vya0IrUUM1aG1hUVFoQXU2ejV0ZStrUHJzUWc0UFEvSkNSTDd2d2VaRXpkZHdsQ284TllHVUpYYVNHMExnMms3d0R4OW9ITFR1QS9UZWxpdDJWcmZnUmJVNlk2ZjZGRU9jempLbkhLZ0hUMDlSSmE1NndkaWhnSHJleVdiVkNDN0JmZEZKMnpSajFmRzVZRWdwa0EzcGdNc3V2VURpNkFpNnROVmUzTzNqQXFDbVhnaHBGYnJ5aTlYWWd0RHNRa3BHUFJVWnlMdk5CajVrOHFCb2lZa2lIUFd2eUlieUI5U1gwcGN5UDEwUjh6UjBUQjhwWFVaYjNYaDFwNFZETVR0ZzV1OFd3ZjU2cElyV2UzS1lqMjBQMndXeVEzZ2xEbzVHTUp4VWRvdWJUeE91bjIrVjBKNk9jMGRLbG13ZXFFakFiYWtKaURkeXZ0eTJPZ2duYmdSU05ZWkluTktWUjluYm5QVUUva0NTTWJOZUU1aFZWRkMweng2RktIa2R4aVpGRXY4YlAvTFI0aFk0OU9FWmE5dnVQUkJuMkxxZmx1Y083d201T25EOG1OM1BZOExscE42U1dDVVRHSjJxZndtMzZ2alJLcEh4bkZINkljeURWd21iUHVsQ01FbmZuTDVyS0ovNGJaR2lFMVNRb2JRR1lEL0dicTFVRldvazBGTWZURlYxd2V0UWZWdjMyU0lTSjZQVUpNMmlUaEJKV0RQTlZUbUtmMjhEbHEyTmFMRk1kMXVnS3hBV1AyZk45WU9ndzZadWlpUkIvNlViSU03TXMyRldmeXRHcDJvWWN5OTRYUAo=

---
apiVersion: v1
kind: Service
metadata:
  name: db-svc
  namespace: default
  labels:
    app: weblog
    type: database
spec:
  ports:
  - port: 27017
    targetPort: 27017
  clusterIP: None
  selector:
    app: weblog
    type: database

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
  namespace: default
  labels:
    app: weblog
    type: database
spec:
  selector:
    matchLabels:
      app: weblog
      type: database
  serviceName: db-svc
  replicas: 3
  template:
    metadata:
      name: mongodb
      namespace: default
      labels:
        app: weblog
        type: database
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: mongodb
        image: weblog-db:v1.0.0
        imagePullPolicy: Never
        args:
        - "mongod"
        - "--auth"
        - "--clusterAuthMode=keyFile"
        - "--keyFile=/home/mongodb/keyfile"
        - "--replSet=rs0"
        - "--bind_ip_all"
        env:
        - name: "MONGO_INITDB_ROOT_USERNAME"
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: root_username
        - name: "MONGO_INITDB_ROOT_PASSWORD"
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: root_password
        - name: "MONGO_INITDB_DATABASE"
          value: "admin"
        volumeMounts:
        - mountPath: /data/db
          name: storage
        - mountPath: /home/mongodb
          name: secret
      volumes:
      - name: secret
        secret:
          secretName: mongo-secret
          items:
          - key: keyfile
            path: keyfile
            mode: 0700
  volumeClaimTemplates:
  - metadata:
      name: storage
    spec:
      storageClassName: slow
      accessModes:
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
```


-----------------------------------------------------------------------------------------------
## DBサーバーの構築（初期化）



1. デバッグ用Podを起動
2. 初期化スクリプトをデバッグ用Podへコピー
3. デバッグ用Podへ入る
4. MongoDBへ接続してプライマリを確認して切断
5. 初期化スクリプトを修正（必要であれば）
6. 初期化スクリプトを実行
7. いずれかのMongoDBに接続してデータが入ったことを確認



```adduser.js
// use weblog
db.createUser({
  user: "user",
  pwd: "welcome",
  roles: [{
    role: "readWrite", db: "weblog"
  }]
})
```



```drop.js
db.posts.drop();
db.users.drop();
db.privileges.drop();
```



```init.sh
# Create user 
mongo mongodb://mongo-0.db-svc:27017/weblog -u admin -p Passw0rd --authenticationDatabase admin ./adduser.js

# Create collection & insert initial data
mongo mongodb://mongo-0.db-svc:27017/weblog -u admin -p Passw0rd --authenticationDatabase admin ./insert.js
```



```insert.js
//
// posts table
//
db.posts.createIndex({ url: 1 }, { unique: true, background: true });
db.posts.insertMany([{
  url: "/2017/05/hello-nodejs.html",
  published: new Date(2017, 4, 2),
  updated: new Date(2017, 4, 2),
  title: "ようこそ Node.js の世界へ",
  content: "Node.js は おもしろい！",
  keywords: ["Node.js"],
  authors: ["Yuta Sato"]
}, {
  url: "/2017/06/nodejs-basic.html",
  published: new Date(2017, 5, 12),
  updated: new Date(2017, 5, 12),
  title: "Node.js の 基本",
  content: "ちょっと難しくなってきた！？",
  keywords: ["Node.js"],
  authors: ["Yuta Sato"]
}, {
  url: "/2017/07/advanced-nodejs.html",
  published: new Date(2017, 7, 8),
  updated: new Date(2017, 7, 8),
  title: "Node.js 応用",
  content: "Node.js で Excel ファイルが触れるなんて！！",
  keywords: ["Node.js"],
  authors: ["Yuta Sato"]
}]);

//
// users table
//
db.users.createIndex({ email: 1 }, { unique: true, background: true });
db.users.insertMany([{
  email: "yuta.sato@sample.com",
  name: "Yuta Sato",
  password: "77d1fb804f4e1e6059377122046c95de5e567cb9fd374639cb96e7f5cc07dba1", //"qwerty", // "77d1fb804f4e1e6059377122046c95de5e567cb9fd374639cb96e7f5cc07dba1"
  role: "owner"
}]);

//
// privileges table
//
db.privileges.createIndex({ role: 1 }, { unique: true, background: true });
db.privileges.insertMany([
  { role: "default", permissions: ["read"] },
  { role: "owner", permissions: ["readWrite"] }
]);
```

-----------------------------------------------------------------------------------------------
## APサーバーのイメージ作成



実装
1. 以下のファイルを作成
    
    ROOT
    │
    │ .dockerignore
    │ docker-entrypoint.sh
    │ Dockerfile
    │
    │    --- 以下は Node.js アプリ Application フォルダに配置---
    │ app.js
    │ package.json
    │ yarn.lock
    │
    ├─ api
    ├─ config
    ├─ lib
    ├─ log
    ├─ public
    ├─ routes
    └─ views


確認
※DBサーバーが起動して初期化まで済んでいること

1. MongoDBのプライマリを確認
2. MongoDBに対するService, Endpointsを作成（kubectl apply）
3. Dockerで作成したイメージを実行（docker run）
4. 作成したNode.jsアプリケーションコンテナへ接続（curl）
5. MongoDB接続用Service, Endpointsを削除（kubectl delete）








-----------------------------------------------------------------------------------------------
## APサーバーの構築（Pod+Secret）



実装
1. 以下のファイルを作成
    weblog-app-pod.yml


確認
※DBサーバーが起動して初期化まで済んでいること

1. Secret, Podを作成（kubectl apply）
2. デバッグPodを作成して入る（kubectl exec）
3. APサーバーPodへ接続確認（curl）



```weblog-app-pod.yml
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
  namespace: default
  labels:
    app: weblog
    type: database
type: Opaque
data:
  root_username: YWRtaW4=
  root_password: UGFzc3cwcmQ=
  weblog_username: dXNlcg==     # user
  weblog_password: d2VsY29tZQ== # welcome
  keyfile: REZDeXROTzBtd2F3eUJzMjVFT3dwdHZDMVRpY1B6STM5S2tvampoZkU3SGVSL1Z2cnllTndxZE92T3dpWjlqUC9wSVdJZVlVWWlrdFpYZlhoT09seU1CRXdVQ0dyK3VtYm1FZXVkdWROeTRoUUNzVmUwWU9TbFgwN1hxYS8vbyttejRaOHBFY2hOMHdVYWhxcEhENWllRnlvTU5JVmFFY0ZQRjQzKzN2Wm92dzdNNHhhWSt4aGhuVzVldGdtL2MyZzlHYUdsSjRhWFBYSmJIUVR5bHNjbml2QnJtV2lJWStKQVBjK29GR0pMNUkzT0NpU1IxZDY2Z0c5OXlzb2Y3NlJ0eDBNdllnV2RYOXJTZTE2b2RhSTNJV3RtaEkyQ0xiV3BTOTk0blljV1RDYnRvcjNmTUMxY3M4bk5SV3kxdW4rSmJiUG9vTXFpUk9ieFJuY0hhcDJYK3BPS3RqWVBnK1lLWDFIdGYrWHlhSDdEckZkWk1uc1ZiQXRBZ1Y2Q2Y2N0laeW02NXA4TGpqRmtoWlRibjVaTWdqUWlud2Vya0IrUUM1aG1hUVFoQXU2ejV0ZStrUHJzUWc0UFEvSkNSTDd2d2VaRXpkZHdsQ284TllHVUpYYVNHMExnMms3d0R4OW9ITFR1QS9UZWxpdDJWcmZnUmJVNlk2ZjZGRU9jempLbkhLZ0hUMDlSSmE1NndkaWhnSHJleVdiVkNDN0JmZEZKMnpSajFmRzVZRWdwa0EzcGdNc3V2VURpNkFpNnROVmUzTzNqQXFDbVhnaHBGYnJ5aTlYWWd0RHNRa3BHUFJVWnlMdk5CajVrOHFCb2lZa2lIUFd2eUlieUI5U1gwcGN5UDEwUjh6UjBUQjhwWFVaYjNYaDFwNFZETVR0ZzV1OFd3ZjU2cElyV2UzS1lqMjBQMndXeVEzZ2xEbzVHTUp4VWRvdWJUeE91bjIrVjBKNk9jMGRLbG13ZXFFakFiYWtKaURkeXZ0eTJPZ2duYmdSU05ZWkluTktWUjluYm5QVUUva0NTTWJOZUU1aFZWRkMweng2RktIa2R4aVpGRXY4YlAvTFI0aFk0OU9FWmE5dnVQUkJuMkxxZmx1Y083d201T25EOG1OM1BZOExscE42U1dDVVRHSjJxZndtMzZ2alJLcEh4bkZINkljeURWd21iUHVsQ01FbmZuTDVyS0ovNGJaR2lFMVNRb2JRR1lEL0dicTFVRldvazBGTWZURlYxd2V0UWZWdjMyU0lTSjZQVUpNMmlUaEJKV0RQTlZUbUtmMjhEbHEyTmFMRk1kMXVnS3hBV1AyZk45WU9ndzZadWlpUkIvNlViSU03TXMyRldmeXRHcDJvWWN5OTRYUAo=

---
apiVersion: v1
kind: Pod
metadata:
  name: nodeapp
  namespace: default
  labels:
    app: weblog
    type: application
spec:
  containers:
  - name: node
    image: weblog-app:v1.0.0
    imagePullPolicy: Never
    ports:
    - containerPort: 3000
    env:
    - name: "MONGODB_USERNAME"
      valueFrom:
        secretKeyRef:
          name: mongo-secret
          key: weblog_username
    - name: "MONGODB_PASSWORD"
      valueFrom:
        secretKeyRef:
          name: mongo-secret
          key: weblog_password
    - name: "MONGODB_HOSTS"
      value: "mongo-0.db-svc:27017,mongo-1.db-svc:27017,mongo-2.db-svc:27017,"
    - name: "MONGODB_DATABASE"
      value: "weblog"
    - name: "MONGODB_REPLICASET"
      value: "rs0"
```




-----------------------------------------------------------------------------------------------
## APサーバーの構築（Deployment）



実装
1. 以下のファイルを作成
    weblog-app-deployment.yml


確認
※DBサーバーが起動して初期化まで済んでいること

1. Secret, Deploymentを作成（kubectl apply）
2. デバッグPodを作成して入る（kubectl exec）
3. APサーバーPodへ接続確認（curl）



```weblog-app-deployment.yml
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
  namespace: default
  labels:
    app: weblog
    type: database
type: Opaque
data:
  root_username: YWRtaW4=
  root_password: UGFzc3cwcmQ=
  weblog_username: dXNlcg==     # user
  weblog_password: d2VsY29tZQ== # welcome
  keyfile: REZDeXROTzBtd2F3eUJzMjVFT3dwdHZDMVRpY1B6STM5S2tvampoZkU3SGVSL1Z2cnllTndxZE92T3dpWjlqUC9wSVdJZVlVWWlrdFpYZlhoT09seU1CRXdVQ0dyK3VtYm1FZXVkdWROeTRoUUNzVmUwWU9TbFgwN1hxYS8vbyttejRaOHBFY2hOMHdVYWhxcEhENWllRnlvTU5JVmFFY0ZQRjQzKzN2Wm92dzdNNHhhWSt4aGhuVzVldGdtL2MyZzlHYUdsSjRhWFBYSmJIUVR5bHNjbml2QnJtV2lJWStKQVBjK29GR0pMNUkzT0NpU1IxZDY2Z0c5OXlzb2Y3NlJ0eDBNdllnV2RYOXJTZTE2b2RhSTNJV3RtaEkyQ0xiV3BTOTk0blljV1RDYnRvcjNmTUMxY3M4bk5SV3kxdW4rSmJiUG9vTXFpUk9ieFJuY0hhcDJYK3BPS3RqWVBnK1lLWDFIdGYrWHlhSDdEckZkWk1uc1ZiQXRBZ1Y2Q2Y2N0laeW02NXA4TGpqRmtoWlRibjVaTWdqUWlud2Vya0IrUUM1aG1hUVFoQXU2ejV0ZStrUHJzUWc0UFEvSkNSTDd2d2VaRXpkZHdsQ284TllHVUpYYVNHMExnMms3d0R4OW9ITFR1QS9UZWxpdDJWcmZnUmJVNlk2ZjZGRU9jempLbkhLZ0hUMDlSSmE1NndkaWhnSHJleVdiVkNDN0JmZEZKMnpSajFmRzVZRWdwa0EzcGdNc3V2VURpNkFpNnROVmUzTzNqQXFDbVhnaHBGYnJ5aTlYWWd0RHNRa3BHUFJVWnlMdk5CajVrOHFCb2lZa2lIUFd2eUlieUI5U1gwcGN5UDEwUjh6UjBUQjhwWFVaYjNYaDFwNFZETVR0ZzV1OFd3ZjU2cElyV2UzS1lqMjBQMndXeVEzZ2xEbzVHTUp4VWRvdWJUeE91bjIrVjBKNk9jMGRLbG13ZXFFakFiYWtKaURkeXZ0eTJPZ2duYmdSU05ZWkluTktWUjluYm5QVUUva0NTTWJOZUU1aFZWRkMweng2RktIa2R4aVpGRXY4YlAvTFI0aFk0OU9FWmE5dnVQUkJuMkxxZmx1Y083d201T25EOG1OM1BZOExscE42U1dDVVRHSjJxZndtMzZ2alJLcEh4bkZINkljeURWd21iUHVsQ01FbmZuTDVyS0ovNGJaR2lFMVNRb2JRR1lEL0dicTFVRldvazBGTWZURlYxd2V0UWZWdjMyU0lTSjZQVUpNMmlUaEJKV0RQTlZUbUtmMjhEbHEyTmFMRk1kMXVnS3hBV1AyZk45WU9ndzZadWlpUkIvNlViSU03TXMyRldmeXRHcDJvWWN5OTRYUAo=

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodeapp
  namespace: default
  labels:
    app: weblog
    type: application
spec:
  replicas: 3
  selector:
    matchLabels:
      app: weblog
      type: application
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  revisionHistoryLimit: 14
  template:
    metadata:
      name: nodeapp
      namespace: default
      labels:
        app: weblog
        type: application
    spec:
      containers:
      - name: node
        image: weblog-app:v1.0.0
        imagePullPolicy: Never
        ports:
        - containerPort: 3000
        env:
        - name: "MONGODB_USERNAME"
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: weblog_username
        - name: "MONGODB_PASSWORD"
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: weblog_password
        - name: "MONGODB_HOSTS"
          value: "mongo-0.db-svc:27017,mongo-1.db-svc:27017,mongo-2.db-svc:27017,"
        - name: "MONGODB_DATABASE"
          value: "weblog"
        - name: "MONGODB_REPLICASET"
          value: "rs0"
```



-----------------------------------------------------------------------------------------------
## APサーバーの構築（Service）



実装
1. 以下のファイルを作成
    weblog-app-fullset.yml


確認
※DBサーバーが起動して初期化まで済んでいること

1. Secret, Deployment, Serviceを作成（kubectl apply）
2. デバッグPodを作成して入る（kubectl exec）
3. APサーバーへService経由で接続（curl）
4. APサーバーのいずれかにログ出力されていることを確認



```weblog-app-fullset.yml
apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
  namespace: default
  labels:
    app: weblog
    type: database
type: Opaque
data:
  root_username: YWRtaW4=
  root_password: UGFzc3cwcmQ=
  weblog_username: dXNlcg==     # user
  weblog_password: d2VsY29tZQ== # welcome
  keyfile: REZDeXROTzBtd2F3eUJzMjVFT3dwdHZDMVRpY1B6STM5S2tvampoZkU3SGVSL1Z2cnllTndxZE92T3dpWjlqUC9wSVdJZVlVWWlrdFpYZlhoT09seU1CRXdVQ0dyK3VtYm1FZXVkdWROeTRoUUNzVmUwWU9TbFgwN1hxYS8vbyttejRaOHBFY2hOMHdVYWhxcEhENWllRnlvTU5JVmFFY0ZQRjQzKzN2Wm92dzdNNHhhWSt4aGhuVzVldGdtL2MyZzlHYUdsSjRhWFBYSmJIUVR5bHNjbml2QnJtV2lJWStKQVBjK29GR0pMNUkzT0NpU1IxZDY2Z0c5OXlzb2Y3NlJ0eDBNdllnV2RYOXJTZTE2b2RhSTNJV3RtaEkyQ0xiV3BTOTk0blljV1RDYnRvcjNmTUMxY3M4bk5SV3kxdW4rSmJiUG9vTXFpUk9ieFJuY0hhcDJYK3BPS3RqWVBnK1lLWDFIdGYrWHlhSDdEckZkWk1uc1ZiQXRBZ1Y2Q2Y2N0laeW02NXA4TGpqRmtoWlRibjVaTWdqUWlud2Vya0IrUUM1aG1hUVFoQXU2ejV0ZStrUHJzUWc0UFEvSkNSTDd2d2VaRXpkZHdsQ284TllHVUpYYVNHMExnMms3d0R4OW9ITFR1QS9UZWxpdDJWcmZnUmJVNlk2ZjZGRU9jempLbkhLZ0hUMDlSSmE1NndkaWhnSHJleVdiVkNDN0JmZEZKMnpSajFmRzVZRWdwa0EzcGdNc3V2VURpNkFpNnROVmUzTzNqQXFDbVhnaHBGYnJ5aTlYWWd0RHNRa3BHUFJVWnlMdk5CajVrOHFCb2lZa2lIUFd2eUlieUI5U1gwcGN5UDEwUjh6UjBUQjhwWFVaYjNYaDFwNFZETVR0ZzV1OFd3ZjU2cElyV2UzS1lqMjBQMndXeVEzZ2xEbzVHTUp4VWRvdWJUeE91bjIrVjBKNk9jMGRLbG13ZXFFakFiYWtKaURkeXZ0eTJPZ2duYmdSU05ZWkluTktWUjluYm5QVUUva0NTTWJOZUU1aFZWRkMweng2RktIa2R4aVpGRXY4YlAvTFI0aFk0OU9FWmE5dnVQUkJuMkxxZmx1Y083d201T25EOG1OM1BZOExscE42U1dDVVRHSjJxZndtMzZ2alJLcEh4bkZINkljeURWd21iUHVsQ01FbmZuTDVyS0ovNGJaR2lFMVNRb2JRR1lEL0dicTFVRldvazBGTWZURlYxd2V0UWZWdjMyU0lTSjZQVUpNMmlUaEJKV0RQTlZUbUtmMjhEbHEyTmFMRk1kMXVnS3hBV1AyZk45WU9ndzZadWlpUkIvNlViSU03TXMyRldmeXRHcDJvWWN5OTRYUAo=

---
apiVersion: v1
kind: Service
metadata:
  name: app-svc
  namespace: default
  labels:
    app: weblog
    type: application
spec:
  ports:
  - port: 3000
    targetPort: 3000
  selector:
    app: weblog
    type: application

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodeapp
  namespace: default
  labels:
    app: weblog
    type: application
spec:
  replicas: 3
  selector:
    matchLabels:
      app: weblog
      type: application
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  revisionHistoryLimit: 14
  template:
    metadata:
      name: nodeapp
      namespace: default
      labels:
        app: weblog
        type: application
    spec:
      containers:
      - name: node
        image: weblog-app:v1.0.0
        imagePullPolicy: Never
        ports:
        - containerPort: 3000
        env:
        - name: "MONGODB_USERNAME"
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: weblog_username
        - name: "MONGODB_PASSWORD"
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: weblog_password
        - name: "MONGODB_HOSTS"
          value: "mongo-0.db-svc:27017,mongo-1.db-svc:27017,mongo-2.db-svc:27017,"
        - name: "MONGODB_DATABASE"
          value: "weblog"
        - name: "MONGODB_REPLICASET"
          value: "rs0"
```






-----------------------------------------------------------------------------------------------
## WEBサーバーのイメージ作成



実装
1. 以下のファイルを作成
    ROOT
      docker-entrypoint.sh
      Dockerfile

  ※nginx.confは添付を利用

確認
※Kubernetes上でDBサーバーとAPサーバーが起動していること

1. APサーバーへアクセスするServiceを作成
2. Webサーバーコンテナ起動
3. 外部からブラウザでアクセスして画面確認



```nginx.conf
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    server_tokens   off;

    proxy_cache_path /var/cache/nginx keys_zone=STATIC:10m max_size=1g inactive=10d;
    proxy_temp_path  /var/cache/nginx/tmp;

    server {
        listen        80;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        location / {
            proxy_pass http://${APPLICATION_HOST}/;
        }

        location /public/ {
            proxy_pass http://${APPLICATION_HOST}/public/;
            proxy_ignore_headers Cache-Control Expires;
            proxy_buffering on;
            proxy_cache STATIC;
            proxy_cache_valid any 10d;
            add_header X-Nginx-Cache $upstream_cache_status;
        }
    }

    # include /etc/nginx/conf.d/*.conf;
}
```



```docker-entrypoint.sh
#! /bin/sh

envsubst '$$APPLICATION_HOST' \
  < /home/nginx/nginx.conf \
  > /etc/nginx/nginx.conf

exec "$@"
```



```Dockerfile
FROM nginx:1.17.2-alpine

COPY . /home/nginx

RUN cd /home/nginx; \
    mv docker-entrypoint.sh /usr/local/bin; \
    chmod +x /usr/local/bin/docker-entrypoint.sh;

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["nginx", "-g", "daemon off;"]



weblog-app-service.yml
apiVersion: v1
kind: Service
metadata:
  name: nodeapp
  namespace: default
  labels:
    env: study
spec:
  type: NodePort
  selector:
    app: weblog
    type: application
  ports:
  - port: 3000
    targetPort: 3000
    nodePort: 30000
```




-----------------------------------------------------------------------------------------------
## WEBサーバーの構築（Pod）

実装
1. 以下のファイルを作成
    weblog-web-pod.yml


確認
※DBサーバーが起動して初期化まで済んでいること
※APサーバーが起動していること

1. ConfigMap, Deployment, Serviceを作成（kubectl apply）
2. 作成したWebサーバーPodのIPアドレスを確認（kubectl get）
3. デバッグPodを作成して入る（kubectl exec）
4. Webサーバーへ接続（curl）
5. 接続したWebサーバーにアクセスログがあることを確認



```weblog-web-pod.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: default
  labels:
    app: weblog
    type: frontend
spec:
  containers:
  - name: nginx
    image: weblog-web:v1.0.0
    imagePullPolicy: Never
    ports:
    - containerPort: 80
    env:
    - name: "APPLICATION_HOST"
      value: "app-svc:3000"
```



-----------------------------------------------------------------------------------------------
## WEBサーバーの構築（Pod+ConfigMap）




実装
1. 以下のファイルを作成
    weblog-web-pod+configmap.yml


確認
※DBサーバーが起動して初期化まで済んでいること
※APサーバーが起動していること

1. ConfigMap, Podを作成（kubectl apply）
2. WebサーバーPodに入ってConfigMapを利用していることを確認（kubectl exec）
3. WebサーバーPodのIPアドレスを確認（kubectl get）
4. デバッグPodを作成して入る（kubectl exec）
5. WebサーバーPodへ接続確認（curl）



```weblog-web-pod+configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: default
  labels:
    app: weblog
    type: frontend
data:
  nginx.conf: |
    user  nginx;
    worker_processes  auto;

    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;


    events {
        worker_connections  1024;
    }


    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        sendfile        on;

        keepalive_timeout  65;

        server_tokens   off;

        proxy_cache_path /var/cache/nginx keys_zone=STATIC:10m max_size=1g inactive=10d;
        proxy_temp_path  /var/cache/nginx/tmp;

        server {
            listen        80;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            location / {
                proxy_pass http://${APPLICATION_HOST}/;
            }

            location /public/ {
                proxy_pass http://${APPLICATION_HOST}/public/;
                proxy_ignore_headers Cache-Control Expires;
                proxy_buffering on;
                proxy_cache STATIC;
                proxy_cache_valid any 10d;
                add_header X-Nginx-Cache $upstream_cache_status;
            }
        }

        # include /etc/nginx/conf.d/*.conf;
        # ConfigMap
    }

---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: default
  labels:
    app: weblog
    type: frontend
spec:
  containers:
  - name: nginx
    image: weblog-web:v1.0.0
    imagePullPolicy: Never
    ports:
    - containerPort: 80
    env:
    - name: "APPLICATION_HOST"
      value: "app-svc:3000"
    volumeMounts:
    - name: config-volume
      mountPath: /home/nginx
  volumes:
  - name: config-volume
    configMap:
      name: nginx-config
```




-----------------------------------------------------------------------------------------------
## WEBサーバーの構築（Deployment）




実装
1. 以下のファイルを作成
    weblog-web-deployment.yml


確認
※DBサーバーが起動して初期化まで済んでいること
※APサーバーが起動していること

1. ConfigMap, Deploymentを作成（kubectl apply）
2. WebサーバーPodのIPアドレスを確認（kubectl get）
3. デバッグPodを作成して入る（kubectl exec）
4. WebサーバーPodいずれかへ接続確認（curl）




```weblog-web-deployment.yml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: default
  labels:
    app: weblog
    type: frontend
data:
  nginx.conf: |
    user  nginx;
    worker_processes  auto;

    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;


    events {
        worker_connections  1024;
    }


    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        sendfile        on;

        keepalive_timeout  65;

        server_tokens   off;

        proxy_cache_path /var/cache/nginx keys_zone=STATIC:10m max_size=1g inactive=10d;
        proxy_temp_path  /var/cache/nginx/tmp;

        server {
            listen        80;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            location / {
                proxy_pass http://${APPLICATION_HOST}/;
            }

            location /public/ {
                proxy_pass http://${APPLICATION_HOST}/public/;
                proxy_ignore_headers Cache-Control Expires;
                proxy_buffering on;
                proxy_cache STATIC;
                proxy_cache_valid any 10d;
                add_header X-Nginx-Cache $upstream_cache_status;
            }
        }

        # include /etc/nginx/conf.d/*.conf;
        # ConfigMap
    }

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
  labels:
    app: weblog
    type: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: weblog
      type: frontend
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  revisionHistoryLimit: 14
  template:
    metadata:
      name: nginx
      namespace: default
      labels:
        app: weblog
        type: frontend
    spec:
      containers:
      - name: nginx
        image: weblog-web:v1.0.0
        imagePullPolicy: Never
        ports:
        - containerPort: 80
        env:
        - name: "APPLICATION_HOST"
          value: "app-svc:3000"
        volumeMounts:
        - name: config-volume
          mountPath: /home/nginx
      volumes:
      - name: config-volume
        configMap:
          name: nginx-config
```



-----------------------------------------------------------------------------------------------
## WEBサーバーの構築（Service）


実装
1. 以下のファイルを作成
    weblog-web-fullset.yml


確認
※DBサーバーが起動して初期化まで済んでいること
※APサーバーが起動していること

1. ConfigMap, Deploymentを作成（kubectl apply）
2. デバッグPodを作成して入る（kubectl exec）
3. WebサーバーServiceへ接続確認（curl）




```weblog-web-fullset.yml
apiVersion: v1
kind: Service
metadata:
  name: web-svc
  namespace: default
  labels:
    app: weblog
    type: frontend
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: weblog
    type: frontend

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: default
  labels:
    app: weblog
    type: frontend
data:
  nginx.conf: |
    user  nginx;
    worker_processes  auto;

    error_log  /var/log/nginx/error.log warn;
    pid        /var/run/nginx.pid;


    events {
        worker_connections  1024;
    }


    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        sendfile        on;

        keepalive_timeout  65;

        server_tokens   off;

        proxy_cache_path /var/cache/nginx keys_zone=STATIC:10m max_size=1g inactive=10d;
        proxy_temp_path  /var/cache/nginx/tmp;

        server {
            listen        80;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Server $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

            location / {
                proxy_pass http://${APPLICATION_HOST}/;
            }

            location /public/ {
                proxy_pass http://${APPLICATION_HOST}/public/;
                proxy_ignore_headers Cache-Control Expires;
                proxy_buffering on;
                proxy_cache STATIC;
                proxy_cache_valid any 10d;
                add_header X-Nginx-Cache $upstream_cache_status;
            }
        }

        # include /etc/nginx/conf.d/*.conf;
        # ConfigMap
    }

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: default
  labels:
    app: weblog
    type: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: weblog
      type: frontend
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  revisionHistoryLimit: 14
  template:
    metadata:
      name: nginx
      namespace: default
      labels:
        app: weblog
        type: frontend
    spec:
      containers:
      - name: nginx
        image: weblog-web:v1.0.0
        imagePullPolicy: Never
        ports:
        - containerPort: 80
        env:
        - name: "APPLICATION_HOST"
          value: "app-svc:3000"
        volumeMounts:
        - name: config-volume
          mountPath: /home/nginx
      volumes:
      - name: config-volume
        configMap:
          name: nginx-config
```


-----------------------------------------------------------------------------------------------
## Webアプリケーションの公開（Ingress）


実装
1. 以下のファイルを作成
    weblog-ingress.yml


確認
※DBサーバーが起動して初期化まで済んでいること
※APサーバーが起動していること
※Webサーバーが起動していること

1. Ingressを作成（kubectl apply）
2. minikubeへ接続確認（ブラウザ）





```weblog-ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: entrypoint
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
  labels:
    app: weblog
    type: entrypoint
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: web-svc
          servicePort: 80
```