ついに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リソース
- まず、mysql用のpersistentVolumeを作成。
- そのpsersistentVolumeからvolumeを要求するPersistentVolumeClaimを作成する。
- mysqlデプロイメントを作成する。
- mysqlデプロイメントをexposeするClusterIPを作成する。
- laravelの環境変数のためにconfigmapを作成する。
- laravelを動かすため、nginxとphp-fpmの2つを含むlaravel-studyDeploymentを作成。
- laravel-studyをexposeするためのNodePortを作成する。
- 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.
この様にログイン機能も動いている事が確認できました。
まとめ
今回はlaravelのスケルトンをデプロイするだけの単純な構成でしたが、どれだけサービスが大きくても基本的なことは今回やったことの積み重ねです。
次回は番外編ではありますが、k8sの見せ所でもあるHorizontalPodAutoscalerで遊んで見よう的な記事を書こうと思います。
これは、サーバーの負荷に応じて、podを自動的にスケールアウトする仕組みです。
apache benchを使い擬似的に半端ないトラフィックを表現して、サーバーにストレスを与えて、それに対応しスケールアウトする様を眺めて遊びましょう。