docker - 在远程 docker swarm 集群上运行手动 GitLab CI 作业时遇到问题
问题描述
这里有一些背景:我有一个在 DigitalOcean Droplet 上运行的 Django 应用程序,预装了 Docker 19.03.1~3。我正在运行一个单节点 swarm 集群,并且该应用程序在大多数情况下运行良好。
这是我遇到的问题:我正在尝试将一些管理命令放入手动触发的 GitLab CI 作业中,因此我不必通过 SSH 连接到 Droplet 并运行命令(migrate
和collectstatic
)。当 SSH 进入 Droplet 时,我可以成功运行这些命令。例如,要运行,collectstatic
我会查找 Django 容器 ( e710394e5449
) 的容器 ID,然后运行:
docker exec -it e710394e5449 python3 manage.py collectstatic
要运行管理命令,我想我可以这样做:
docker exec $(docker ps -q -f name="backend") python3 manage.py collectstatic --no-input
这是我在 GitLab CI 作业日志中看到的错误:
error during connect: Get http://docker/v1.40/containers/e710394e5449/json: command [ssh -l root 123.45.6.789 -- docker system dial-stdio] has exited with exit status 255, please make sure the URL is valid, and Docker 18.09 or later is installed on the remote host: stderr=ssh: connect to host 123.45.6.789 port 22: Connection refused
你可以docker exec
从远程 docker 主机上的 GitLab CI 作业运行吗?我能够获取容器 ID ( $(docker ps -q -f name="backend")
),但外部docker exec
命令失败。 docker exec $(docker ps -q -f name="backend") python3 manage.py collectstatic --no-input
我可以毫无问题地从我的笔记本电脑上运行命令 ( )。
这是我的.gitlab-ci.yml
文件。该django-collectstatic
作业对于我如何运行命令有两种选择:一种用于docker exec
在现有容器中运行命令,另一种使用docker run
. 这些选项都不起作用,这只是为了展示我尝试过的内容。
stages:
- build
- deploy
- management
workflow:
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: always
image: docker:19.03.1
services:
- docker:19.03.5-dind
.add-ssh-key: &add-ssh-key
before_script:
- apk update && apk add openssh-client bash
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- eval "$(ssh-agent -s)"
- ssh-add ~/.ssh/id_rsa
- ssh-keyscan -H $DROPLET_IP >> ~/.ssh/known_hosts
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
build-backend:
stage: build
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
script:
- |
docker build \
-t $CI_REGISTRY_IMAGE/backend:$CI_COMMIT_SHORT_SHA \
-f backend/docker/Dockerfile.prod \
./backend/
- docker push $CI_REGISTRY_IMAGE/backend:$CI_COMMIT_SHORT_SHA
build-nginx:
stage: build
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
script:
- |
docker build \
-t $CI_REGISTRY_IMAGE/nginx:$CI_COMMIT_SHORT_SHA \
-f nginx/prod/Dockerfile \
.
- docker push $CI_REGISTRY_IMAGE/nginx:$CI_COMMIT_SHORT_SHA
docker-stack-deploy:
<<: *add-ssh-key
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: delayed
start_in: 1 minute
stage: deploy
variables:
DOCKER_HOST: "ssh://root@$DROPLET_IP"
script:
- docker stack deploy --with-registry-auth -c stack.yml my-stack
.task-base: &task-base
<<: *add-ssh-key
stage: management
variables:
DOCKER_HOST: "ssh://root@$DROPLET_IP"
rules:
- when: manual
django-collectstatic:
<<: *task-base
script:
# should I do this?
- docker exec $(docker ps -q -f name="backend") python3 manage.py collectstatic --no-input
# or this? or something else?
# - |
# docker run \
# --rm \
# --network main \
# -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
# -e SECRET_KEY=$SECRET_KEY \
# -e DEBUG=$DEBUG \
# -e DOMAIN_NAME=$DOMAIN_NAME \
# -v backendassets:/code/assets \
# $CI_REGISTRY_IMAGE/backend:$CI_COMMIT_SHORT_SHA \
# python3 manage.py collectstatic --no-input
django-migrate:
<<: *task-base
script:
- docker exec $(docker ps -q -f name="backend") python3 manage.py migrate --no-input
django-createsuperuser:
<<: *task-base
script:
- docker exec $(docker ps -q -f name="backend") python3 manage.py createsuperuser --no-input
请让我知道我是否可以提供任何其他信息来帮助澄清我的问题。
解决方案
目前,我认为最简单的方法是直接通过 SSH 运行 docker 命令,而不是使用DOCKER_HOST
环境变量连接我的 docker CLI(在 GitLab CI 中)。
这最终看起来像这样:
django-migrate:
before_script:
- apk update && apk add openssh-client bash
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- eval "$(ssh-agent -s)"
- ssh-add ~/.ssh/id_rsa
- ssh-keyscan -H $DROPLET_IP >> ~/.ssh/known_hosts
stage: management
rules:
- when: manual
script:
- ssh root@$DROPLET_IP \
'docker exec $(docker ps -q -f name="backend") python3 manage.py migrate --no-input'
无论出于何种原因,运行docker exec $(docker ps -q -f name="backend") python3 manage.py migrate --no-input
都会失败。我将能够获取容器 ID(该docker ps
命令将成功完成,但该docker exec
命令将因连接被拒绝而失败。
我不确定通过 SSH 连接运行 docker 命令的安全性。
该命令的输出确实很好地显示在 GitLab CI 作业的日志中,这正是我想要的。
推荐阅读
- tmux - 使用 tmux 时如何禁用滚动功能?
- vba - WORD - 通过引号中的文本查找和替换文本
- java - 如果被调度作业调用 Dropwizar ,则看不到标有 @Timed 注释的方法
- javascript - 如何在整个文档中搜索特定单词及其前一个单词(在 java 脚本中)
- npm - 如何在 npmjs 上取消发布节点模块?
- powershell - 从远程系统运行 Get-PSDrive 时的 AUDIT_FAILURE
- xslt-2.0 - XML 到 CSV(使用输入日期生成新日期)
- javascript - 如何取消嘲笑要求?
- selenium - 在测试套件中运行特定测试 - Selenium Side Runner (IDE)
- c# - 集合和迭代器的 C# 性能