LaravelAPPをk8sでデプロイ(ついにminikubeへデプロイ)

kubernetes

ついにKubernetesへデプロイ

DockerImageの作成でしばらくk8sとは遠ざかっていたので久しぶりのk8sネタとなります。

前回DockerHubへPushしたデプロイ用のDockerImageを使い、kubernetesで動作させます。

まずはdocker-composeファイルで構成をおさらい

version: '3.7'

services:
  laravel-study:
    container_name: laravel-study
    build:
      context: .
      dockerfile: Dockerfile.php
    image: kamayla/laravel-study
    networks:
    - laravel_study-network

  nginx-study:
    build:
      context: .
      dockerfile: Dockerfile.nginx
    image: kamayla/nginx-study
    container_name: nginx-study
    ports:
    - 8080:80
    networks:
    - laravel_study-network
    depends_on:
    - laravel-study

ここで抑えることは、まず、コンテナが2つあること。

laravel-studyというのはphp-fpmコンテナでした。

これは9000番ポートで待ち受けています。

次に、nginx-studyはnginxコンテナでした。

こちらは8080番ポートで待ち受けています。

nginxからphp-fpmへの通信の引き渡しはnginxの設定ファイル内部で既に設定済みでしたね。

また、mysqlは公式イメージを使い実装するのでした。こちらは3306番ポートで待ち受けています。

このことからkubernetesで実装しなければならないリソースをまとめて行きましょう。

実装するk8sリソース

  1. まず、mysql用のpersistentVolumeを作成。
  2. そのpsersistentVolumeからvolumeを要求するPersistentVolumeClaimを作成する。
  3. mysqlデプロイメントを作成する。
  4. mysqlデプロイメントをexposeするClusterIPを作成する。
  5. laravelの環境変数のためにconfigmapを作成する。
  6. laravelを動かすため、nginxとphp-fpmの2つを含むlaravel-studyDeploymentを作成。
  7. laravel-studyをexposeするためのNodePortを作成する。
  8. ingressを作成し、path「/」のターゲットをlaravel-studyのServiceの8080番ポートに向ける。

以上が基本的な流れとなります。

必要ファイルは以下にまとめてあります。
https://github.com/kamayla/kube-study-standard/tree/master/9_laravel_deploy/k8s

1. まず、mysql用のpersistentVolumeを作成

まずはminikubeをstart。

$ minikube start

続いて、minikubeの中にmysqlのデータを保存するためのディレクトリを作成します。

minikubeの中に入る。

$ minikube ssh

こんなのが表示されてttyが確立されます。

~$ minikube ssh
                         _             _
            _         _ ( )           ( )
  ___ ___  (_)  ___  (_)| |/')  _   _ | |_      __
/' _ ` _ `\| |/' _ `\| || , <  ( ) ( )| '_`\  /'__`\
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )(  ___/
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____)

$

待受でpwdと打ちましょう。

$ pwd
/home/docker

現在いる場所がわかりました。2つ上のルートに行きたいので次のコマンドを。

$ cd ../../

ルートのディレクトリをみてみましょう。

$ ls
bin  data  dev  etc  home  init  lib  lib64  libexec  linuxrc  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

なにやらいっぱいありますが、こんかい重要なのはマウント用のディレクトリであるmntです。これに移動します。

$ cd mnt

そしてここにmysql用のディレクトリを作成しましょう。

$ sudo mkdir mysql-study
$ ls
mysql-study  vda1

mysqlディレクトリが追加されています。これで下準備はOKです。

mysql-study-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-study-pv
spec:
  storageClassName: manual
  capacity:
    storage: 100M
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/mysql-study"

hostPathで先程作成したmysql-studyディレクトリを指定しています。

コレに納得したらapplyします。

kubectl apply -f mysql-study-pv.yaml

2. そのpsersistentVolumeからvolumeを要求するPersistentVolumeClaimを作成する。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-study-pvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10M

先程作成したpersistentVolumeから10M拝借するPersistentVolumeClaimです。

これを実際にコンテナに対してマウントすることになります。

この内容に納得したら次のコマンドでapplyします。

$ kubectl apply -f mysql-study-pvc.yaml
$ kubectl get pv,pvc
NAME                              CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                     STORAGECLASS   REASON   AGE
persistentvolume/mysql-study-pv   100M       RWO            Retain           Bound    default/mysql-study-pvc   manual                  33s

NAME                                    STATUS   VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/mysql-study-pvc   Bound    mysql-study-pv   100M       RWO            manual         22s

statusがBoundとなっているのが上手くできている証です。

3. mysqlデプロイメントを作成する。

mysqlは公式ImageにEnvを設定するのみ。

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    run: study-db
  name: study-db
spec:
  replicas: 1
  selector:
    matchLabels:
      run: study-db
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: study-db
    spec:
      containers:
      - image: mysql:5.7.28
        name: study-db
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: docker
        - name: MYSQL_DATABASE
          value: database
        - name: MYSQL_USER
          value: docker
        - name: MYSQL_PASSWORD
          value: docker
        volumeMounts:
        - name: mysql-study-storage
          mountPath: /var/lib/mysql
        ports:
        - containerPort: 3306
        resources: {}
      volumes:
      - name: mysql-study-storage
        persistentVolumeClaim:
          claimName: mysql-study-pvc
status: {}

こいつもapplyしちゃいましょう。

kubectl apply -f deploy_db.yaml

4. mysqlデプロイメントをexposeするClusterIPを作成する。

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    run: study-db
  name: study-db
spec:
  ports:
  - port: 3306
    protocol: TCP
    targetPort: 3306
  selector:
    run: study-db
  type: ClusterIP
status:
  loadBalancer: {}

もう何度も出てきているので説明は不要かとは思いますが、mysqlを3306でCluster内部に公開します。

こいつもapplyしましょう。

 kubectl apply -f service_db.yaml

5. laravelの環境変数のためにconfigmapを作成する

実は今回DockerHubにPushしたイメージにはlaravelのenvファイルが含まれていません。

それはImageにDBの情報などの環境変数を含めたくなかったからです。

その代わりに、k8sリソースであるconfigMapによってenvファイルを表現できます。

以下がconfigMapリソースを作成するためのyamlファイルです。

apiVersion: v1
data:
  APP_NAME: Laravel
  APP_ENV: local
  APP_KEY: base64:okx7eCW7n0cYmJIl+No57TPmpSozfUIUn2t8wT+7+AQ=
  APP_DEBUG: 'true'
  APP_URL: http://localhost

  LOG_CHANNEL: stack

  DB_CONNECTION: mysql
  DB_HOST: study-db
  DB_PORT: '3306'
  DB_DATABASE: database
  DB_USERNAME: docker
  DB_PASSWORD: docker

  BROADCAST_DRIVER: log
  CACHE_DRIVER: file
  QUEUE_CONNECTION: sync
  SESSION_DRIVER: file
  SESSION_LIFETIME: '120'

  REDIS_HOST: '127.0.0.1'
  REDIS_PASSWORD: 'null'
  REDIS_PORT: '6379'

  MAIL_DRIVER: smtp
  MAIL_HOST: smtp.mailtrap.io
  MAIL_PORT: '2525'
  MAIL_USERNAME: 'null'
  MAIL_PASSWORD: 'null'
  MAIL_ENCRYPTION: 'null'

  AWS_ACCESS_KEY_ID: 'null'
  AWS_SECRET_ACCESS_KEY: 'null'
  AWS_DEFAULT_REGION: us-east-1
  AWS_BUCKET: 'null'

  PUSHER_APP_ID: 'null'
  PUSHER_APP_KEY: 'null'
  PUSHER_APP_SECRET: 'null'
  PUSHER_APP_CLUSTER: mt1

  MIX_PUSHER_APP_KEY: "${PUSHER_APP_KEY}"
  MIX_PUSHER_APP_CLUSTER: "${PUSHER_APP_CLUSTER}"
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: laravel-study-config

dataの中に見慣れた.envの記述が見受けられると思います。

こうすることでこのconfigMapをマウントしたコンテナはこれらの環境変数を使用することができます。

こいつもapplyしましょう。

kubectl apply -f configmap.yaml

6. laravelを動かすため、nginxとphp-fpmの2つを含むlaravel-studyDeploymentを作成

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    run: laravel-study
  name: laravel-study
spec:
  replicas: 1
  selector:
    matchLabels:
      run: laravel-study
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: laravel-study
    spec:
      containers:
      - image: kamayla/laravel-study
        name: laravel-study
        ports:
        - containerPort: 9000
        envFrom:
          - configMapRef:
              name: laravel-study-config
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 30m
            memory: 30Mi

      - image: kamayla/nginx-study
        name: nginx-study
        ports:
        - containerPort: 80
        envFrom:
          - configMapRef:
              name: laravel-study-config
        resources:
          limits:
            cpu: 100m
            memory: 100Mi
          requests:
            cpu: 30m
            memory: 30Mi
      volumes:
        - name: laravel-study-config
          configMap:
            name: laravel-study-config
status: {}

containersの中のimageのところで指定している名前が、前回の記事でdockerhubにpushしたImageになります。

ここではkamayla/nginx-stiudyとkamayla/laravel-studyをコンテナイメージとして指定し、先程作成したconfigMapをenvFromで指定することで、コンテナ内部の環境変数として定義しています。

これもapplyしましょう。

$ kubectl apply -f deploy_laravel.yaml

7. laravel-studyをexposeするためのNodePortを作成する。

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    run: laravel-study
  name: laravel-study
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 80
  selector:
    run: laravel-study
  type: NodePort
status:
  loadBalancer: {}

laravel-studyを8080番ポートで外部にexposeし、この場合targetPortが80番なので、このPod内のnginxへ通信が届きます。

これもapplyしましょう。

$ kubectl apply -f service_laravel.yaml

この時点で既に、NodePort経由であればLaravelは既に公開されています。

NAME                                 READY   STATUS    RESTARTS   AGE
pod/laravel-study-7b4b6f8779-rq8w6   2/2     Running   0          6m19s
pod/study-db-78b87b8fd9-84l7k        1/1     Running   0          21m

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/laravel-study   1/1     1            1           6m19s
deployment.apps/study-db        1/1     1            1           21m

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP          22d
service/laravel-study   NodePort    10.103.119.150   <none>        8080:30496/TCP   2m4s
service/study-db        ClusterIP   10.106.84.204    <none>        3306/TCP         18m

NAME                              CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                     STORAGECLASS   REASON   AGE
persistentvolume/mysql-study-pv   100M       RWO            Retain           Bound    default/mysql-study-pvc   manual                  26m

NAME                                    STATUS   VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/mysql-study-pvc   Bound    mysql-study-pv   100M       RWO            manual         25m

NAME                             DATA   AGE
configmap/laravel-study-config   36     17d

この中のServiceのNodePortの外部公開ポートである30496でアクセスしてみましょう。

minikubeの場合minikubeのipとこのportでアクセスすることが可能です。

まずはminikubeのipを知りましょう。

$ minikube ip
192.168.64.6

上記のコマンドを打ってでてくるIPでアクセスしてください。私の場合は192.168.64.6でした。

このようにNodePort経由でデプロイ出来ていることが確認できますが、これではまだ本番運用には使えません。

続いてIngressとNodePortを接続しましょう。

8. ingressを作成し、path「/」のターゲットをlaravel-studyのServiceの8080番ポートに向ける。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: laravel-study
  # annotations:
  #   nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: laravel-study
          servicePort: 8080

上記がIngressを形作る設定ファイルです。

ルートパスに対してlaravel-studyのサービスと8080ポートの指定をしています。

これもapplyします。

k apply -f ingress.yaml

続いて、先程のminikube ipに直接アクセスしましょう。

先程との違いはポートナンバー無しでアクセスできています。

これはingressを経由して、laravel-studyのNodePortへアクセスしているからです。

LaravelのMigrationをしてDBまわりの動作確認

とりあえずlaravelのphp側のコンテナに入ってmigrationコマンドを実行しましょう。

kubectl exec -it laravel-study-7b4b6f8779-rq8w6 --container=laravel-study sh

-itの後の名前の指定はkubectl get podで取得されるpodの名前を指定してください。

--containerの指定は、今回の場合はpodに対して2つのコンテナが含まれています。

なので入り込みたいコンテナ名を指定する必要があります。

ちなみにDockerなどでもよく出てくる-itはinteractive Tele-TYpewriterの略で、日本語で言うところの、対話形式で遠くの人とタイピングで会話するやつ的な意味合い。

Teleってのが遠くのって意味合いですね。

無事コンテナの中に入れたらお馴染みのコマンドを打ち込みましょう。

# php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (0.01 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (0.01 seconds)

ついでなんで認証機能も生成しちゃいましょう。

# php artisan make:auth
Authentication scaffolding generated successfully.

Image from Gyazo

この様にログイン機能も動いている事が確認できました。

まとめ

今回はlaravelのスケルトンをデプロイするだけの単純な構成でしたが、どれだけサービスが大きくても基本的なことは今回やったことの積み重ねです。

次回は番外編ではありますが、k8sの見せ所でもあるHorizontalPodAutoscalerで遊んで見よう的な記事を書こうと思います。

これは、サーバーの負荷に応じて、podを自動的にスケールアウトする仕組みです。

apache benchを使い擬似的に半端ないトラフィックを表現して、サーバーにストレスを与えて、それに対応しスケールアウトする様を眺めて遊びましょう。

タイトルとURLをコピーしました