データベースにデータを保存するアプリケーションは、機能開発やバグ等でのデプロイ時にほとんどのケースで、最初にデータのマイグレーションを実施する必要があります。
目次
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へのロジックは共通化でき、エントリポイントを分けることができるのでおすすめです。お疲れさまでした。