Jenkins pipeline中使用docker运行Ansible时失败

85次阅读
没有评论

*
fatal: [destination.box.local]: UNREACHABLE! => {“changed”: false, “msg”: “argument must be an int, or have a fileno() method.”, “unreachable”: true}

用户还提到,使用本地安装的Ansible而不是docker(使用`agent any`)的类似Jenkins pipeline可以正常工作。
## 解决方案
> 请注意以下操作注意版本差异及修改前做好备份。
### 方案1
在用户的情况下,问题是由于Jenkins使用特定的UID和GID运行docker agent导致的。为了解决这个问题,需要重新构建docker镜像,并创建具有相同UID和GID的内部Jenkins用户。
以下是解决方案的步骤:
1. 在Jenkinsfile的顶部添加以下代码,用于获取当前用户的UID和GID:
```groovy
def user_id
def group_id
node {
   user_id = sh(returnStdout: true, script: 'id -u').trim()
   group_id = sh(returnStdout: true, script: 'id -g').trim()
}
  1. 在构建阶段将额外的参数传递给docker,如下所示:
--build-arg JenkinsUserId=${user_id} --build-arg JenkinsGroupId=${group_id}
  1. 在Dockerfile中,根据提供的参数创建Jenkins用户,并将其添加到root组中:
FROM alpine:latest

# 获取提供的参数
ARG JenkinsUserId
ARG JenkinsGroupId

# 创建Ansible配置目录
RUN set -xe \
    && mkdir -p /etc/ansible

# 创建Ansible临时目录
RUN set -xe \
    && mkdir -p /.ansible/tmp

# 设置ANSIBLE_LOCAL_TEMP环境变量
ENV ANSIBLE_LOCAL_TEMP /.ansible/tmp

# 创建Ansible控制路径目录
RUN set -xe \
    && mkdir -p /.ansible/cp

# 设置ANSIBLE_SSH_CONTROL_PATH_DIR环境变量
ENV ANSIBLE_SSH_CONTROL_PATH_DIR /.ansible/cp

# 创建Jenkins组和用户
RUN if ! id $JenkinsUserId; then \
    groupadd -g ${JenkinsGroupId} jenkins; \
    useradd jenkins -u ${JenkinsUserId} -g jenkins --shell /bin/bash --create-home; \
  else \
    addgroup --gid 1000 -S jenkins && adduser --uid 1000 -S jenkins -G jenkins; \
  fi

# 将Jenkins用户添加到root组
RUN addgroup jenkins root

# 告诉docker以后的所有命令都应该以jenkins用户身份运行
USER jenkins
  1. 最后,更新主pipeline中的docker agent,如下所示:
agent {
   docker {
      image 'artifactory.devbox.local/docker-local/myrepo/jdk8:latest'
      args '-v $HOME/.m2:/root/.m2 -v $HOME/.ssh:/home/jenkins/.ssh  -v /etc/ansible:/etc/ansible -v $HOME/.ansible/tmp:/.ansible/tmp -v $HOME/.ansible/cp:/.ansible/cp'
   }
}

通过以上步骤,您应该能够解决在Jenkins pipeline中使用docker运行Ansible时遇到的问题。

方案2

如果方案1无法解决问题,您可以尝试使用其他方法来控制容器的运行顺序。例如,您可以使用docker run命令手动控制容器的启动顺序,或者使用一些第三方工具来管理容器的依赖关系。
请注意,这种方法可能会增加复杂性,并且需要确保容器A和容器B之间的依赖关系正确设置。
以下是一个简单的bash脚本示例,可以在容器A启动后启动容器B:

#!/bin/bash
# 启动容器A
docker run -d --name container_a your_image_a
# 等待容器A完全启动
while ! docker exec container_a echo "Container A is ready"; do
  sleep 1
done
# 启动容器B
docker run -d --name container_b your_image_b

在这个示例中,我们首先使用docker run命令启动容器A,并将其命名为container_a。然后,使用一个循环来等待容器A完全启动(这里是通过在容器内运行echo命令来测试)。一旦容器A就绪,我们再使用docker run命令启动容器B,并将其命名为container_b
通过以上方法,您可以手动控制容器的启动顺序,以满足您的需求。

正文完