🕷

minikubeでマルチサービスを立ち上げる(1)

2021/03/26に公開

kubernetesの勉強のために、Minikubeでマルチサービスを立ち上げます。
ボリュームが大きいので複数回に分けて紹介していきます。

ソースコードはこちらに記載していきます。
https://github.com/tkomatsu/mini_services

初回は1つのサービスを立ち上げ、ホストから確認できるまでをまとめます。
環境構築に関しては、今回の記事では扱いません。
Minikube, kubectl, Dockerを適宜インストールしておいてください。

今回実装するもの

  • nginx
  • WordPress
  • phpMyAdmin
  • mariaDB
  • InfluxDB
  • Grafana
  • ftps

基本的に公式のイメージを使用しますが、ftpsは公式イメージが見つからなかったためAlpineベースのイメージを作成する予定です。
また、Minikubeでは外部のロードバランサーが使えないため、MetalLBを使用します。

minikubeを起動する

下記コマンドを実行します。

minikube start --driver=docker
minikube status # minikubeが立ち上がっているかの確認

最初のサービスを立ち上げる

一番シンプルにできる(であろう)nginxを立ち上げていきながら、基本的な流れを追っていきます。
公式のイメージに一手間加え、オレオレ証明書によるhttps接続などを追加します。
そのため、Dockerfileを以下のように作成し、コンテナイメージをビルドします。

Dockerfile
FROM nginx
RUN mkdir /etc/nginx/ssl && openssl genrsa -out /etc/nginx/ssl/server.key 2048 && openssl req -new -x509 -days 3650 -key /etc/nginx/ssl/server.key -out /etc/nginx/ssl/server.crt -subj "/C=JP/ST=Tokyo/"
COPY nginx.conf /etc/nginx/conf.d/default.conf
nginx.conf
server {
	listen 80;
	listen [::]:80;

	server_name	_;

	return 301 https://$host$request_uri;
}

server {
	listen 443 ssl default_server;
	listen [::]:443 ssl default_server;

	server_name _;

	ssl_certificate /etc/nginx/ssl/server.crt;
	ssl_certificate_key /etc/nginx/ssl/server.key;

	root /usr/share/nginx/html;

	index index.html;

	location / {
		try_files $uri $uri/ =404;
	}
}

ホストマシンで、Minikube組み込みのDockerデーモンを操作できるようにするために下記のコマンドを実行します。

eval $(minikube -p minikube docker-env)

コマンド実行後にdocker imagesを実行するとkubernetes関連のコンテナイメージがあり、MinikubeのDockerデーモンにつながっていることが確認できるはずです。
docker buildで今回使用するnginxのイメージを作成しましょう。

kubernetesのマニフェストのファイルを以下のように作成します。

nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: Never
        ports:
        - containerPort: 80
          name: http
        - containerPort: 443
          name: https

オブジェクトの種類にDeploymentを指定しています。
DeploymentオブジェクトがReplicaSetオブジェクトを管理し、RepricaSetがPodを管理します。
spec.replicasの値で複製するPodの個数を指定できます。
立ち上げるPodはspec.templateで指定しています。
spec.template.spec.containersで使用するコンテナの指定をしています。
spec.template.spec.containers.imageでイメージの指定、spec.template.spec.containers.portsで開放するポートを指定しています。
これ以外にも環境変数やマウントボリュームの設定を行うこともでき、それらは他のサービスの実装時に説明します。
docker run-pオプションや-e, -vオプションだと思ってもらえればいいです。

spec.template.spec.containers.imagePullPolicyの項目を記載しない場合はAlwaysとして設定されます。
リポジトリからイメージを取得する設定となりますが、今回はDokerHubを使用せずローカルのイメージを使用するため、Neverを設定しています。

yamlファイルが作成できたらkubernetesに反映させていきましょう。

kubectl apply -f nginx-deployment.yaml

kubectl get allで起動していることを確認します。

$ kubectl get all
NAME                        READY   STATUS    RESTARTS   AGE
pod/nginx-c7d66576c-vsfqc   1/1     Running   0          3s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   57m

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           3s

NAME                              DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-c7d66576c   1         1         1       3s

立ち上がったPodでシェルを立ち上げ、Dockerfileやマニフェストで設定したものが反映されているのかを確認しましょう。
kubectl exec <pod> -- <command>で指定したポッドでコマンドを実行できます。

kubectl exec -it nginx-c7d66576c-vsfqc -- sh

続いて、nginxサーバーが正しく機能しているのかを確認します。

$ kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE   READINESS GATES
nginx-c7d66576c-vsfqc   1/1     Running   0          4m19s   172.17.0.3   minikube   <none>           <none>

Minikube内でのIPアドレスが確認できたので、Minkube内に新たに検証用のPodを立てて接続を確認しましょう。

$ kubectl run busybox --image=busybox --restart=Never --rm -it sh
If you don't see a command prompt, try pressing enter.
/ # wget -q -O - http://172.17.0.3
wget: note: TLS certificate validation not implemented
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

ホストでwgetやcurl、ブラウザでアクセスしようとしても返ってこないので、次に外部に公開する設定をしていきましょう。

ロードバランサの導入

minikubeでは外部のロードバランサが使用できないため、MetalLBを使用します。
Minikubeのアドオン、マニフェスト、kustomizeのいずれかでインストールできます。
今回はマニフェストでインストールすることにします。

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.6/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.6/manifests/metallb.yaml
# On first install only
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"

完了すると以下のようにPodが確認できます。

$ kubectl get pod -n metallb-system
NAME                          READY   STATUS    RESTARTS   AGE
controller-64f86798cc-bmt6g   1/1     Running   0          3m11s
speaker-785lf                 1/1     Running   0          3m11s

これだけではMetalLBが待機状態になっているので、公式ドキュメントの方法にならってconfigを追加します。

metallb-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.49.50 - 192.168.49.60

ファイルが作成できたら反映させます。

kubectl apply -f metallb-configma.yaml

続いて、nginxのServiceを立ち上げていきます。
Serviceの説明は公式ドキュメントを参照します。

Kubernetesにおいて、ServiceはPodの論理的なセットや、そのPodのセットにアクセスするためのポリシーを定義します(このパターンはよくマイクロサービスと呼ばることがあります)。 ServiceによってターゲットとされたPodのセットは、たいてい セレクター (セレクターなしのServiceを利用したい場合は下記を参照してください)によって定義されます。

例えば、3つのレプリカが稼働しているステートレスな画像処理用のバックエンドを考えます。これらのレプリカは代替可能です。— フロントエンドはバックエンドが何であろうと気にしません。バックエンドのセットを構成する実際のPodのセットが変更された際、フロントエンドクライアントはその変更を気にしたり、バックエンドのPodのセットの情報を記録しておく必要はありません。

Serviceによる抽象化は、クライアントからバックエンドのPodの管理する責務を分離することを可能にします。

Serviceを導入することで適宜名前解決をしてくれるようになります。
ロードバランサだけでなく、のちに出てくるDBとの接続の際にも活用していきます。

nginxのServiceのマニフェストは以下のようにします。

nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx
  annotations:
    metallb.universe.tf/allow-shared-ip: mini_services
spec:
  selector:
    app: nginx
  type: LoadBalancer
  ports:
  - name: http
    port: 80
  - name: https
    port: 443

複数のサービスに同一のIPアドレスでアクセスできるようにmetadata.annotations.metallb.universe.tf/allow-shared-ipを設定します。
spec.selectorでServiceで指定したいDeploymentを記載します。
ファイルができたら反映させます。

kubectl apply -f nginx-service.yaml

ここまでできたら、実際にホストから接続できるのかを確認します。

$ kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)                      AGE
kubernetes   ClusterIP      10.96.0.1       <none>          443/TCP                      102s
nginx        LoadBalancer   10.101.60.141   192.168.49.50   80:30047/TCP,443:30638/TCP   71s

EXTERNAL-IPが設定されているのがわかります。
ホストマシンで接続を確認しましょう。

$ curl -IkL 192.168.49.50:80
HTTP/1.1 301 Moved Permanently
Server: nginx/1.19.8
Date: Fri, 26 Mar 2021 04:15:50 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://192.168.49.50/

HTTP/1.1 200 OK
Server: nginx/1.19.8
Date: Fri, 26 Mar 2021 04:15:50 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 09 Mar 2021 15:27:51 GMT
Connection: keep-alive
ETag: "604793f7-264"
Accept-Ranges: bytes

80番ポートから443番ポートにリダイレクトされていることが確認できます。
ブラウザからアクセスすればnginxのインデックスページが表示されるはずです。

終わりに

今回は以下のオブジェクトの実装を行いました。より詳しく知りたい場合は公式のAPIリファレンスを参照してください。

  • Pod
  • ReplicaSet
  • Deployment
  • Service
  • MetalLB(LoadBalancer)

kubernetesでの基本的な流れが掴めたと思うので、次回以降他のサービスを立ち上げていきます。

Discussion