我正在将我的Phoenix应用程序推出到Kubernetes集群,以便通过GitLab进行测试。一旦我的应用程序和postgres服务准备就绪,我希望能够在gitlab-ci.yml
脚本中运行mix ecto.migrate
。以下是gitlab-ci.yml
文件中的一个片段:
review:
stage: review
image: dtzar/helm-kubectl
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://$CI_PROJECT_NAME-${CI_ENVIRONMENT_SLUG}.$KUBE_DOMAIN
on_stop: stop_review
before_script:
- command deploy/kinit.sh
script:
- helm upgrade --install db --wait --set postgresDatabase=app_db stable/postgresql
- helm upgrade --install app ./deploy/app_chart --wait --set env.DATABASE_URL="${DATABASE_URL}"
- export POD_NAME=`kubectl get pod -l "app=${CI_ENVIRONMENT_SLUG}" -o jsonpath='{.items[0].metadata.name}'`
- kubectl exec $POD_NAME -- mix ecto.migrate
据我所知,--wait
参数意味着每个部署都将在继续之前完成(全部)。我发现,尽管postgres部署已经完成,但这并不意味着postgres服务器已经准备好了。
通常情况下,当kubectl exec
命令运行时,我会得到以下错误:
** (exit) exited in: :gen_server.call(#PID<0.183.0>, {:checkout, #Reference<0.0.1.2678>, true, :infinity}, 5000)
** (EXIT) time out
(db_connection) lib/db_connection/poolboy.ex:112: DBConnection.Poolboy.checkout/3
(db_connection) lib/db_connection.ex:919: DBConnection.checkout/2
(db_connection) lib/db_connection.ex:741: DBConnection.run/3
(db_connection) lib/db_connection.ex:1132: DBConnection.run_meter/3
(db_connection) lib/db_connection.ex:584: DBConnection.prepare_execute/4
(ecto) lib/ecto/adapters/postgres/connection.ex:93: Ecto.Adapters.Postgres.Connection.execute/4
(ecto) lib/ecto/adapters/sql.ex:243: Ecto.Adapters.SQL.sql_call/6
(ecto) lib/ecto/adapters/sql.ex:193: Ecto.Adapters.SQL.query!/5
当我查看Kubernetes ui时,我可以在postgres pod中看到以下错误:
SchedulerPredicates failed due to PersistentVolumeClaim is not bound: "db-postgresql", which is unexpected.
看到这条消息后,我监测了吊舱,一切都很好。但在我的部署脚本失败之前。
我最初的想法是,我可以为我的应用程序创建一个initContainer
,它使用psql成功连接到服务器,并检查"app_db"数据库的存在。这样,我就不必担心为超时和重试编写自己的代码——我可以利用Kubernetes提供的内置机制。
但是,我不想在我的生产环境中这样做(我想在生产系统上手动运行mix ecto.migrate
)。在这种情况下,initContainer
只是浪费了系统资源。
有没有一种强大的方法可以通过gitlab-ci.yml
脚本实现这一点?
从概念的角度来看,我会:
-
在我的Postgres容器上配置一个就绪探测器,这样在引擎启动之前,Pod不会被视为"正在运行"。
# in the Pod template: # spec.containers['postgres'] readinessProbe: exec: command: - psql - -U - postgres - -c - 'SELECT 1' initialDelaySeconds: 5 periodSeconds: 5
-
在执行Mix任务之前,请等待Pod转换到"正在运行"状态。
# in gitlab-ci.yml, before "mix ecto.migrate" - | while [ "$(kubectl get pod $POD_NAME -o jsonpath='{$.status.phase}')" != "Running" ]; do sleep 1; done