Help us understand the problem. What is going on with this article?

KubernetesとNode.jsでマイクロサービスを作成する 6/6 Kubernetes with minikube

More than 1 year has passed since last update.

第6章 Kubernetes with minikube

いよいよKubernetesを使ってマイクロサービスを構築していきます。

本章では、ローカル環境で簡単にKubernetes環境を構築できるminikubeを使ってKubernetes上にマイクロサービスを構築します。

チュートリアル全体

構成

microservice-tutorial01.png

minikubeとkubectlの準備

まずは、Kubernetesをローカル環境で再現できるminikubeを準備します。
公式ドキュメントにしたがってインストールを行います。

インストールが完了したら下記コマンドでminikubeを起動します。

minikube start

※ 私の環境はLinux Mintなのですが、VirtualBox版の起動がうまくいかないため、minikube start --vm-driver kvmでKVM版を起動しています。

ingressアドオンを有効にします。(少し時間がかかります)

minikube addons enable ingress

minikubeでは、下記のコマンドを実行することで、ダッシュボードにブラウザでアクセスできます。

minikube dashboard

ブラウザで自動で下記のダッシュボードが開かれます。(画像では既に本章で構築するマイクロサービスが稼働している状態です)

k8s_01.png

続いて、Kubernetesをコマンドラインから操作するkubectlコマンドをインストールします。
公式ドキュメントの説明に沿ってインストールします。

インストールできたら、minikubeを認識しているか、下記のコマンドで確認してみましょう。
currentの*がminikubeについていれば問題ありません。
(既にGKE等の別のKubernetes環境を利用している場合はkubectl config use-context minikubeで切り替えましょう)

kubectl config get-contexts
CURRENT   NAME       CLUSTER    AUTHINFO   NAMESPACE
*         minikube   minikube   minikube

以上でminikubeとkubectlの準備は完了です。

minikubeにDockerイメージを登録する

dockerコマンドが利用するdocker enginをminikubeのものに変更します。

eval $(minikube docker-env)

次に前章で作成したmicroservice-sample-integrationリポジトリのmake buildでDockerイメージを作成し、minikubeのイメージリポジトリへ登録します。

cd path/to/microservice-sample-integration
make build

以上でminikube上へDockerイメージをpushできました。

yamlファイルによるKubernetesの設定

それでは、Kubernetesの設定を記述していきます。
Kubernetesはkubectlコマンドやダッシュボードを利用した操作の他に、マニュフェストファイルというyaml形式で記述されたファイルを利用した操作が可能と成っています。
おそらく、ほとんどの現場ではこのマニュフェストファイルでの管理を実施しているはずだと思います。

今回作成する各マニュフェストファイルと、それぞれの役割について紹介します。

  • tweet-db.yml
    • Tweetサービスのデータベースです
    • PersistentVolumeを使いデータの永続化を行います
    • StatefulSetを使い、MongoDBのクラスター構成を構築できるようにします
  • tweet.yml
    • Tweetサービスです
    • k8sのServiceとDeploymentを記述します
  • user-db.yml
    • Userサービスのデータベースです
    • tweet-dbとほぼ同じ設定です
  • user.yml
    • Userサービスです
    • k8sのServiceとDeploymentを記述します
  • web.yml
    • Webサービスです
  • ingress.yml
    • ロードバランサーの設定です
  • cluster-role.yml
    • Kubernetes APIのRoleを設定します
    • MongoDBのside carからAPIを利用するために作成します

それでは、詳細に1ファイルずつ確認していきます。

tweet-db.yml

Tweetサービスのデータベース用のサービスの設定です。

複数のノードからなるデータベースはステートフルのため、少し工夫が必要です。
公式ブログのRunning MongoDB on Kubernetes with StatefulSetsを参考に実装しています。

manifests/tweet-db.yml
---
apiVersion: v1
kind: Service
metadata:
  name: tweet-db
  labels:
    name: tweet-db
spec:
  ports:
    - port: 27017
      targetPort: 27017
  clusterIP: None
  selector:
    app: tweet-db
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: tweet-db
spec:
  selector:
    matchLabels:
      app: tweet-db
  serviceName: tweet-db
  replicas: 3
  template:
    metadata:
      labels:
        app: tweet-db
    spec:
      terminationGracePeriodSeconds: 10
      containers:
        - name: tweet-db
          image: mongo
          command:
            - mongod
            - "--bind_ip"
            - 0.0.0.0
            - "--replSet"
            - rs0
            - "--smallfiles"
            - "--noprealloc"
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: tweet-db-pvc
              mountPath: /data/db
        - name: tweet-db-sidecar
          image: cvallance/mongo-k8s-sidecar
          env:
            - name: MONGO_SIDECAR_POD_LABELS
              value: "app=tweet-db"
            - name: KUBERNETES_MONGO_SERVICE_NAME
              value: tweet-db
  volumeClaimTemplates:
    - metadata:
        name: tweet-db-pvc
      spec:
        accessModes:
          - "ReadWriteOnce"
        resources:
          requests:
            storage: 100Mi

tweet.yml

TweetサービスのNode.jsで実装したAPI部分を動かす部分です。コンテナを動かすDeploymentとそれをクラスター内へ公開するServiceを定義しています。

manifests/tweet.yml
---
apiVersion: v1
kind: Service
metadata:
  name: tweet-service
spec:
  ports:
    - port: 3000
      targetPort: 3000
  selector:
    app: tweet
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tweet-deployment
  labels:
    app: tweet
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tweet
  template:
    metadata:
      labels:
        app: tweet
    spec:
      containers:
        - name: tweet
          image: microservice_tweet:1.0
          ports:
            - containerPort: 3000
          env:
            - name: MONGODB_URL
              value: mongodb://tweet-db:27017/tweet?replicaSet=rs0
            - name: WAIT_HOSTS
              value: tweet-db:27017

user-db.yml

UserサービスのDB部分です。tweet-db.ymlとほぼ同じ構成です。

manifests/user-db.yml
---
apiVersion: v1
kind: Service
metadata:
  name: user-db
  labels:
    name: user-db
spec:
  ports:
    - port: 27017
      targetPort: 27017
  clusterIP: None
  selector:
    app: user-db
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: user-db
spec:
  selector:
    matchLabels:
      app: user-db
  serviceName: user-db
  replicas: 3
  template:
    metadata:
      labels:
        app: user-db
    spec:
      terminationGracePeriodSeconds: 10
      containers:
        - name: user-db
          image: mongo
          command:
            - mongod
            - "--bind_ip"
            - 0.0.0.0
            - "--replSet"
            - rs0
            - "--smallfiles"
            - "--noprealloc"
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: user-db-pvc
              mountPath: /data/db
        - name: user-db-sidecar
          image: cvallance/mongo-k8s-sidecar
          env:
            - name: MONGO_SIDECAR_POD_LABELS
              value: "app=user-db"
            - name: KUBERNETES_MONGO_SERVICE_NAME
              value: user-db
  volumeClaimTemplates:
    - metadata:
        name: user-db-pvc
      spec:
        accessModes:
          - "ReadWriteOnce"
        resources:
          requests:
            storage: 100Mi

user.yml

UserサービスのAPI部分です。こちらもtweet.ymlとほぼ同じ構成です。

manifests/user.yml
---
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  ports:
    - port: 3000
      targetPort: 3000
  selector:
    app: user
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-deployment
  labels:
    app: user
spec:
  replicas: 1
  selector:
    matchLabels:
      app: user
  template:
    metadata:
      labels:
        app: user
    spec:
      containers:
        - name: user
          image: microservice_user:1.0
          ports:
            - containerPort: 3000
          env:
            - name: MONGODB_URL
              value: mongodb://user-db:27017/user?replicaSet=rs0
            - name: WAIT_HOSTS
              value: user-db:27017

web.yml

Webサービスでは、GitHubのOAuth用環境変数をSecretから取得する設定にしています。
Secretの作成は後述します。

manifests/web.xml
---
apiVersion: v1
kind: Service
metadata:
  name: web-service
  labels:
    app: web-service
spec:
  ports:
    - port: 3000
      targetPort: 3000
  selector:
    app: web
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
  labels:
    app: web
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: microservice_web:1.0
          ports:
            - containerPort: 3000
          env:
            - name: GITHUB_CLIENT_ID
              valueFrom:
                secretKeyRef:
                  name: github-oauth
                  key: GITHUB_CLIENT_ID
            - name: GITHUB_CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: github-oauth
                  key: GITHUB_CLIENT_SECRET
            - name: CALLBACK_URL
              value: http://microservice.test/callback
            - name: BASE_URL
              value: http://microservice.test
            - name: NUXT_HOST
              value: 0.0.0.0
            - name: USER_SERVICE
              value: http://user-service:3000
            - name: TWEET_SERVICE
              value: http://tweet-service:3000
      dnsConfig:
        nameservers:
          - 8.8.8.8

ingress.yml

Ingressを利用してWebサービスを公開します。
Ingressを利用することで、AWSならALB、GCPならLoadBalancerを作成してくれます。
k8sでのサービスの公開方法はいくつかありますが、この記事が参考になります。

manifests/ingress.yml
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress
spec:
  rules:
    - host: microservice.test
      http:
        paths:
          - backend:
              serviceName: web-service
              servicePort: 3000

cluster-role.yml

manifests/cluster-role.yml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: admin
rules:
- apiGroups: [""]
  resources: ["pods", "nodes"]
  verbs: ["get", "watch", "list"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: rbac
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: rbac.authorization.k8s.io

サービスを構築する

それでは、作成したマニュフェストファイルを使い、サービスが稼働するように構築していきます。

minikubeはローカルPC上のVMで稼働しているため、エンドポイントがminikubeのIPとなってしまいます。
Ingressの設定をhttpで作成したので、この場合は、http://<minikubeのIP>がwebサービスのエンドポイントになっています。
今回はこのIPアドレスにhostsでmicroservice.testという名前をつけ、エンドポイントをhttp://microservice.testという形でアクセスするように設定しましょう。

最終的には下図のような構成となります。
minikube.png

OAuth設定の作成

エンドポイントが変更になったので、前章までのlocalhost:3000用のOAuth設定は利用できません。
新しいOAuth設定を作成します。

こちらを参考に、GitHubでOAuth用のClientIDとClientSecretを取得してください。
その際、callbackURLはhttp://microservice.test/callbackとします。

作成したOAuth設定のIDとSecretは.env.minikubeに以下の形式で設定しておきましょう。

.env.minikube
GITHUB_CLIENT_ID=xxxxxxxxxxxxxx
GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxx

hostsの設定

minikubeのIPをmicroservice.testという名前でhostsに設定します。
minikubeのIPはminikube ipコマンドで取得できます。

/etc/hosts
# 略
192.168.42.242 microservice.test

Secretの作成

先ほど作成したGitHubのOAuth設定をSecretというKubernetesの機能を利用して、Kubernetes上から参照できるようにします。

以下のコマンドでファイルを指定してSecretが作成できます。

kc create secret generic github-oauth --from-env-file .env.minikube

作成できたらダッシュボードから確認してみましょう。
ダッシュボードはminikube dashboardで開くことができます。

kubectlで構築

それでは、kubectlコマンドでマニュフェストファイルを利用しサービスを構築していきます。

kubectl apply -f manifests/cluster-role.yml
kubectl apply -f manifests/tweet-db.yml
kubectl apply -f manifests/tweet.yml
kubectl apply -f manifests/user-db.yml
kubectl apply -f manifests/user.yml
kubectl apply -f manifests/web.yml
kubectl apply -f manifests/ingress.yml

作成できたら、ブラウザでhttp://microservice.testへアクセスしてみましょう。
userやtweetを何も作成していないため、データは表示されませんが、下記コマンドで前章と同様にデータを投入できます。

kubectl exec <user/tweetのpod名> node scripts/initialize.sh
# deployment名は下記コマンドで確認可能
kubectl get pods

無事にサービスが動いていれば、本章のチュートリアルは完了です。

その他デバッグに役立つコマンド

# ターミナル接続
kubectl -it exec <pod名> sh
# ログの確認(ダッシュボード上でも確認可能)
kubectl logs -f <pod名>

まとめ

本章ではminikubeを使い、ローカルPC上に構築したKubernetesに対し、マイクロサービスを構築しました。

以上で本チュートリアルは終了です。
いかがだったでしょうか?
不足している点などは、今後追記していこうかと思います。

ありがとうございました。

reireias
ヘルステック系ベンチャーのMENSAフルスタックSRE
https://reireias.github.io/
medpeer
国内医師の3人に1人が参加する国内有数のUGC型ドクタープラットフォーム「MedPeer」や遠隔医療サービスなどを運営するヘルステックカンパニー
https://medpeer.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした