データベースにデータを保存するアプリケーションは、機能開発やバグ等でのデプロイ時にほとんどのケースで、最初にデータのマイグレーションを実施する必要があります。
目次
goのデータベースマイグレーションツール
goのデータベースマイグレーションツールは色々あります。よく利用するのは、gooseとgolang-migrateです。
goose
goのデータベースマイグレーションツールとしてよく名前に上がるものにgooseがあります。多くのドライバ、S3、Google Storageなどへの移行をサポートしています。
golang-migrate
golang-migrateは、多くのドライバをサポートしています。up, down, forceというシンプルなコマンドをサポートしています。
マイグレーションのアプローチ
データ移行用のプログラムと通常稼働時のロジックは、分けるように実装します。コンテナ化をベースに考える場合には、データ移行コンテナ、通常稼働用のコンテナという形で実装します。
コードは共通化するがエントリポイントを分ける
ソースコードを書いていると、データベースアクセスするロジックなど共通になる部分が多くなるので、同一プロジェクトレイアウトで扱えるような仕組みが嬉しいです。下記例では、migrationコマンドでDBマイグレーションを行い、serverコマンドでREST APIサーバとして起動するようなバイナリを作っています。DBのマイグレーションは、InitContainerで実行する形で行っています。
{{- $containerPort := 80 -}}
{{- $appName := "sample-usr-api" -}}
{{- $serviceName := "sample-user-api-svc" -}}
{{- $deploymentName := "sample-user-api-deployment" -}}
apiVersion: v1
kind: Service
metadata:
name: {{ $serviceName }}
spec:
type: ClusterIP
selector:
app: {{ $appName }}
ports:
- protocol: TCP
nodePort: null
port: 8080
targetPort: {{ $containerPort }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $deploymentName }}
spec:
selector:
matchLabels:
app: {{ $appName }}
replicas: 1
template:
metadata:
labels:
app: {{ $appName }}
spec:
initContainers:
- name: migration-task
image: {{ .Values.userapi.repository }}:{{ .Values.container.tag }}
command: [ "./sample-api", "migrate", "up" ]
env:
- name: POSTGRES_USER
value: apiadmin
- name: POSTGRES_PASSWORD
value: apiadmin
- name: POSTGRES_HOST
value: "sample-postgres-svc"
- name: POSTGRES_PORT
value: "5432"
- name: DB_NAME
value: "sample_db"
containers:
- name: sample-user-api
image: {{ .Values.userapi.repository }}:{{ .Values.container.tag }}
command: [ "./sample-api", "server" ]
ports:
- containerPort: {{ $containerPort }}
env:
- name: POSTGRES_USER
value: apiadmin
- name: POSTGRES_PASSWORD
value: apiadmin
- name: POSTGRES_HOST
value: "sample-postgres-svc"
- name: POSTGRES_PORT
value: "5432"
- name: DB_NAME
value: "sample_db"
commandで実行できるようにしておけば、InitContainerで紹介したコンテナを起動して、マイグレーションを行っているロジックをJobとして切り出すこともできるので、コマンドベースで作成しておくと同一DBへのロジックは共通化でき、エントリポイントを分けることができるのでおすすめです。お疲れさまでした。

