はじめに
2023年アドベントカレンダー最終日です。
昨日と今日で、k8sの環境をskaffoldで作っています。
本日は立ち上げの最後までいきます。
各Dockerfileの作成
各サービスを立ち上げるためのDockerfileを作成します。
ディレクトリ構造のイメージとしてはこのような感じです
.
├── api
├── bff
├── dockers
| ├── api
| | └── Dockerfile
| ├── bff
| | └── Dockerfile
| ├── db
| | ├── init.sql
| | └── Dockerfile
| └── web
| └── Dockerfile
└── web
Web
WebはNext.jsで動きます。
nodejs
のイメージを使い、build
してから、start
するような形が良いでしょう
FROM node:21-alpine3.17
WORKDIR /life-sync-web
COPY ./web /life-sync-web
RUN npm install && npm run build
CMD ["npm", "run", "start"]
BFF
BFFはNestJSで動きます。
nodejs
のイメージを使い、prod
モードで起動するようにstart:prod
しようと思います
FROM node:21-alpine3.17
WORKDIR /life-sync-bff
COPY ./bff /life-sync-bff
RUN npm install
CMD ["npm", "run", "start:prod"]
API
APIはRustで動きます。
nodejs
のイメージを使い、cargo run
します。
FROM rust:1.73-buster
WORKDIR /life-sync-api
COPY ./api /life-sync-api
CMD ["cargo", "run"]
DB
DBはpostgresqlで動かします。
起動後に、init.sql
を動かしたいので、Dockerfileを作っていきます
CREATE TABLE blog (
id UUID PRIMARY KEY,
title VARCHAR(255) NOT NULL,
author VARCHAR(255) NOT NULL,
body TEXT NOT NULL,
created_at VARCHAR(255) NOT NULL
);
FROM postgres:16
COPY ./dockers/db/init.sql /docker-entrypoint-initdb.d/
Skaffold
Skaffoldとは、Googleによって開発されたKubernates開発のためのコマンドラインツールです。
Skaffoldについては私が所属するUzabaseの先輩が書いた素晴らしい記事があるので、こちらをお読みください
Skaffold.yaml
Skaffold.yamlを作成しました。
apiVersion: skaffold/v2beta19
kind: Config
build:
artifacts:
- image: life-sync-web
context: .
docker:
dockerfile: ./dockers/web/Dockerfile
- image: life-sync-bff
context: .
docker:
dockerfile: ./dockers/bff/Dockerfile
- image: life-sync-api
context: .
docker:
dockerfile: ./dockers/api/Dockerfile
- image: life-sync-db
context: .
docker:
dockerfile: ./dockers/db/Dockerfile
deploy:
kubectl:
manifests:
- k8s/web/*.yaml
- k8s/bff/*.yaml
- k8s/api/*.yaml
- k8s/db/*.yaml
portForward:
- resourceType: service
resourceName: life-sync-web
namespace: default
port: 3000
localPort: 3000
- resourceType: service
resourceName: life-sync-bff
namespace: default
port: 3000
localPort: 4000
- resourceType: service
resourceName: life-sync-api
namespace: default
port: 3000
localPort: 8000
- resourceType: service
resourceName: life-sync-db
namespace: default
port: 5432
localPort: 5432
上から順に、
- DockerImageを指定して
- deployのためのmanifestファイルの場所を指定して
- portを開放する
といった感じです
manifestファイル
.
├── api
├── bff
├── dockers
├── k8s
| ├── api
| | ├── deployment.yaml
| | └── service.yaml
| ├── bff
| | ├── deployment.yaml
| | └── service.yaml
| ├── db
| | ├── service.yaml
| | └── statefulset.yaml
| └── web
| | ├── deployment.yaml
| | └── service.yaml
└── web
Web
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: life-sync-web
spec:
replicas: 1
selector:
matchLabels:
app: life-sync-web
template:
metadata:
labels:
app: life-sync-web
spec:
containers:
- name: life-sync-web
image: life-sync-web:latest
ports:
- containerPort: 3000
service.yaml
apiVersion: v1
kind: Service
metadata:
name: life-sync-web
spec:
selector:
app: life-sync-web
ports:
- protocol: TCP
port: 3000
targetPort: 3000
type: LoadBalancer
BFF
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: life-sync-bff
spec:
replicas: 1
selector:
matchLabels:
app: life-sync-bff
template:
metadata:
labels:
app: life-sync-bff
spec:
containers:
- name: life-sync-bff
image: life-sync-bff:latest
ports:
- containerPort: 3000
service.yaml
apiVersion: v1
kind: Service
metadata:
name: life-sync-bff
spec:
selector:
app: life-sync-bff
ports:
- protocol: TCP
port: 3000
targetPort: 3000
type: LoadBalancer
API
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: life-sync-api
spec:
replicas: 1
selector:
matchLabels:
app: life-sync-api
template:
metadata:
labels:
app: life-sync-api
spec:
containers:
- name: life-sync-api
image: life-sync-api:latest
ports:
- containerPort: 3000
service.yaml
apiVersion: v1
kind: Service
metadata:
name: life-sync-api
spec:
selector:
app: life-sync-api
ports:
- protocol: TCP
port: 3000
targetPort: 3000
type: LoadBalancer
DB
service.yaml
apiVersion: v1
kind: Service
metadata:
name: life-sync-db
spec:
ports:
- protocol: TCP
port: 5432
targetPort: 5432
selector:
app: life-sync-db
type: ClusterIP
statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: life-sync-db
spec:
serviceName: life-sync-db
replicas: 1
selector:
matchLabels:
app: life-sync-db
template:
metadata:
labels:
app: life-sync-db
spec:
containers:
- name: life-sync-db
image: life-sync-db:latest
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: life-sync
- name: POSTGRES_USER
value: postgres_user
- name: POSTGRES_PASSWORD
value: postgres_password
起動
これで起動してみます!
今回の設定とは別で各サービスで他サービスを指定している個所をENVに移行したり、CORSの設定をしたりしました。本題とはずれるので省略しました。
skaffold dev
起動ができました。
直接DBに入り、データをいくつか入れてみました。
データ投入方法
psql
を利用して、直接アクセスしました。
psql -h localhost -p 5432 -U postgres_user -W -d life-sync
好みに合わせて、A5M2や、DBeaverなどのGUIツールを入れてもいいでしょう
ちゃんと表示されました👍
最後に・アドベントカレンダーを振り返って
去年は一貫性の無いアドベントカレンダーを走りましたが、今年は一つのアプリを構築してみました。
そのため、ユーザーストーリー、デザイン、Webの実装、BFFの実装、APIの実装、各種テスト・モック、K8s環境構築といったWebアプリケーションを作る上で必要な一通りの実装を触ることができました。
(実際にクラウド上にデプロイするとなると、もう少しネットワーク関係やセキュリティ面でやることはあるでしょう)
25個の記事を書くのは大変でしたが、楽しかったです
来年も頑張るぞ!