Docker安装Jenkins并支持Maven,Docker,Helm

Docker 安装 Jenkins 很简单, 可是安装完的 Jenkins 并不直接支持 maven, docker 等 CI 经常使用工具. 特别是 docker 涉及到 docker中运行docker, 也就是 docker in docker 的问题. 本文将示例如何解决.html

本示例所用主机 ttg12 的环境为:git

  • IP: 192.168.31.12,
  • OS: ubuntu server 18.04,
  • Docker 版本: 19.03.6.

一. Docker 安装 Jenkins

Jenkins如今也分长期支持版(LTS)和普通支持版, 对于须要线上长期稳定支持的, 最好下载 LTS 版. 当前 (2020.7) jenkins 最新 LTS 版本为 2.235.1-lts.github

# 下载镜像
sudo docker pull jenkins/jenkins:2.235.1-lts
# 新建容器并启动
sudo docker run -d -p 8081:8080 -p 50001:50000 \
    -v /data2/jenkins/jenkins_home:/var/jenkins_home \
    -v /etc/localtime:/etc/localtime:ro \
    --restart=always \
    --name dao_jenkins_1 \
    jenkins/jenkins:2.235.1-lts

其中 2 个 Volumn Mapping 说明以下.spring

  • -v /data2/jenkins/jenkins_home:/var/jenkins_home, docker 中 /var/jenkins_home 是 jenkins 的 $HOME 以及全部配置, 数据存储的地方, 因此必须持久化到本地.
  • -v /etc/localtime:/etc/localtime:ro, 保持 docker 中的时区跟 host 保持一致, 不然日志等时间都使用 UTC+0 时区, 跟中国时间差 8 个小时.

查看容器日志:docker

sudo docker logs dao_jenkins_1

显示权限错误:apache

touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

这是由于 jenkins 在 host 上用户为当前用户 faceless, 而 host 本地目录 /data2/jenkins/jenkins_home 属于 root. json

简单的解决方案, 就是将 /data2/jenkins/jenkins_home 的全部者 (owner) 修改成 host 上运行 docker 用户 faceless (uid=1000)ubuntu

# 修改 faceless 为 host 上 运行 docker 的用户
sudo chown -R faceless /data/jenkins/jenkins_home 
# sudo chown -R faceless /var/run/docker.sock
sudo docker start dao_jenkins_1

而后再重启 jenkins 容器 dao_jenkins_1安全

sudo docker restart dao_jenkins_1

二. 支持 Docker

咱们将 Jenkins 运行在容器中, 而 Jenkins CI 也须要运行 docker 的话, 就会遇到 docker in docker 的问题. 具体请参考: ~jpetazzo/Using Docker-in-Docker for your CI or testing environment? Think twice.. bash

而咱们知道, Docker 其实分为两部分: 服务端和客户端. 服务端经过 socket 套接字 或者监听端口接受客户端的命令. 具体可参考官方文档 Configure where the Docker daemon listens for connections.

也就是说若是咱们在宿主机上运行了 docker 服务端的话, 咱们在容器内能够只安装 docker 客户端, 而后经过 socket套接字 或者 ip+端口 的方式来直接使用宿主的docker 服务. 这样在容器内新建容器, 实际上是在宿主机上新建容器.

由于 Docker 服务端和客户端默认使用 socket 套接字进行交互, 因此咱们这里也使用 socket套接字 的方案, 即将宿主机的 /var/run/docker.sock 经过映射给 Jenkins 容器.

2.1 让容器使用宿主的docker

按照上面的思路, 咱们在建立容器的 docker run 命令中增长以下 3 个参数:

-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker 
-v /etc/docker:/etc/docker \

有关三者的说明

  • -v /var/run/docker.sock:/var/run/docker.sock, 经过映射主机的套接字文件到容器, 让容器内启动 docker 的时候并非启动容器内的容器(子容器), 而是启动主机上的容器(兄弟容器).
  • -v /usr/bin/docker:/usr/bin/docker, 让容器中直接使用宿主机的 docker 客户端.
  • -v /etc/docker:/etc/docker, 让容器中的 docker 客户端使用宿主机的 docker 配置文件, 包括国内镜像 (mirrors) 和 非ssl安全访问白名单 等配置.

2.2 解决访问宿主 socket 的权限问题

重启容器后, 咱们经过 docker exec -it dao_jenkins_1 /bin/bash 命令进入容器, 执行 docker ps 验证 docker 命令是否可正常使用, 结果发现会遇到以下权限问题:

jenkins@f9fd87225ddb:/$ docker ps
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/json: dial unix /var/run/docker.sock: connect: permission denied

咱们先看下 host 上 /var/run/docker.sock 的权限:

faceless@ttg12:~$ ll /var/run/docker.sock
srw-rw---- 1 root docker 0 Jul 16 10:17 /var/run/docker.sock=

能够看到 docker.sock 属于 root 用户 和 docker 组. 映射到容器内的权限为:

jenkins@5affdae1637b:/$ ls -al /var/run/docker.sock
srw-rw---- 1 root 128 0 Jul 16 10:17 /var/run/docker.sock

咱们再在容器查看下 jenkins 用户的 user id 和 groupd id:

jenkins@5affdae1637b:/$ id
uid=1000(jenkins) gid=1000(jenkins) groups=1000(jenkins)

咱们能够看到 jenkins 的用户id 为 1000, group id 也为 1000. 所以咱们的解决方案也有 2 个:

  • 在宿主机将 socket 文件的全部者改成 user id = 1000 的用户;
  • 在给容器内的用户增长 group id = 128 的权限.

下面分别讲解.

2.2.1 修改宿主机 socket 文件权限设置

将 host 上 docker socket 的拥有者修改成运行 uid=1000 的用户, 或者直接将权限修改成其余人可读写666:

# 修改宿主机上 socket 的 owner 为 id=1000 的用户
sudo chown 1000 /var/run/docker.sock
# 或修改 sock 的权限为 666
sudo chmod 666 /var/run/docker.sock

这个方案无需重启容器, 直接在容器内运行 docker ps 能够看到能输出正常结果.

这个方案是网上大多数文章给出的方案. 可是该方案有一个比较的缺陷, 那就是若是宿主机或者 docker 重启, 会从新建立 docker.sock 文件, 其全部者会被重置为 root 用户, 因此咱们又须要再执行上面的命令修改权限.

2.2.2 给予容器 docker 组权限

第二个方案是, 咱们给容器内的 jenkins 用户增长 id=128 的组权限. 而正好 docker run 很友好地提供 groupd-add 参数支持该操做.

官方文档 Additional groups🔗

--group-add: Add additional groups to run as
By default, the docker container process runs with the supplementary groups looked up for the specified user. If one wants to add more to that list of groups, then one can use this flag:

$ docker run --rm --group-add audio --group-add nogroup --group-add 777 busybox id

uid=0(root) gid=0(root) groups=10(wheel),29(audio),99(nogroup),777

也就是说咱们可一个经过 group-add 参数给容器中的用户经过 group name 或者 group id 添加多个额外的用户组权限, 可是注意: 这个用户组是指容器内的用户组, 其 id 可能跟宿主机上的 id 不一致. 而咱们要让容器内的用户拥有 host 的某个 group 权限, 须要经过 id 来赋权.

所以这里咱们先看 host 上 docker 组的 id.

faceless@ttg12:~$ cat /etc/group | grep docker
[sudo] password for weiping:
docker:x:128:weiping

能够看到 docker 用户组的 id 为 128. 所以咱们在建立容器的时候加上 --group-add=128 便可让容器内的 jenkins 用户拥有 /var/run/docker.sock 文件的读写权限:

# 先移除旧容器
sudo docker rm -f dao_jenkins_1
# 从新建立容器
sudo docker run -d -p 8081:8080 -p 50001:50000 \
    -v /data2/jenkins/jenkins_home:/var/jenkins_home \
    -v /etc/localtime:/etc/localtime:ro \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /etc/docker:/etc/docker \
    -v /usr/bin/docker:/usr/bin/docker \
    --restart=always  \
    --group-add=128 \
    --name dao_jenkins_1 \
    jenkins/jenkins:2.235.1-lts

2.2.3 自定义 Dockerfile

其余可能的解决方案 (还未验证), 自定义 Dockerfile (参考自 Use docker inside docker with jenkins user:

FROM jenkins:2.32.3

USER root
RUN apt-get -qq update \
   && apt-get -qq -y install \
   curl

RUN curl -sSL https://get.docker.com/ | sh

RUN usermod -a -G staff jenkins

USER jenkins

三. 安装其余 CI 工具

3.1 安装和配置 Maven

首先安装 maven:

mkdir -p /opt/ && \
cd /opt/ && \
curl -fsSL https://mirror.bit.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz > /tmp/apache-maven-3.6.3-bin.tar.gz && \
tar xzf /tmp/apache-maven-3.6.3-bin.tar.gz -C /opt/ && \
rm /tmp/apache-maven-3.6.3-bin.tar.gz && \
ln -s /opt/apache-maven-3.6.3/bin/mvn /bin/mvn && \
ln -s /opt/apache-maven-3.6.3/bin/mvnyjp /bin/mvnyjp && \
export PATH=/opt/apache-maven-3.6.3/bin:$PATH

而后配置和加速 maven:
1) 在 host 目录 /data2/jenkins/jenkins_home/ (对应 docker 的 /var/jenkins_home/) 中打开或新建 .m2/settings.xml 文件, 添加阿里云镜像:

<mirrors>
    <mirror>
      <id>ali-public</id>
      <mirrorOf>public</mirrorOf>
      <name>aliyun maven public</name>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
    <mirror>
      <id>ali-central</id>
      <mirrorOf>central</mirrorOf>
      <name>aliyun maven central</name>
      <url>https://maven.aliyun.com/repository/central</url>
    </mirror>
        <mirror>
      <id>aligoogle</id>
      <mirrorOf>google</mirrorOf>
      <name>aliyun google</name>
      <url>https://maven.aliyun.com/repository/google</url>
    </mirror>
        <mirror>
      <id>alisping</id>
      <mirrorOf>spring</mirrorOf>
      <name>aliyun spring</name>
      <url>https://maven.aliyun.com/repository/spring</url>
    </mirror>
        <mirror>
      <id>alispringplugin</id>
      <mirrorOf>spring-plugin</mirrorOf>
      <name>aliyun spring-plugin</name>
      <url>https://maven.aliyun.com/repository/spring-plugin</url>
    </mirror>
  </mirrors>

2) 甚至能够把本地 repository 里面已经下载好的三方库都 copy 到 .m2/repository, 节约下载时间.

3.2 支持 Kubernetes Helm

对 Kubernetes Helm3 的支持比较简单, 直接将宿主机上的 helm 映射到容器中便可. 注意这里针对 helm3, 由于 helm3 中已经移除 tiller, 只须要客户端便可.

先将 k8s master 上的 .kube/config 文件复制到 docker 宿主机 (这里是ttg12) 的 /data2/jenkins/jenkins_home/.kube/ 目录下.

而后在 docker run 命令中增长以下映射, 并重建容器.

-v /usr/local/bin/helm:/bin/helm

3.3 提交修改到新镜像 Image

待 docker-ce 安装完成后, 提交本次更新为新的 image, 后面从这个 image 启动容器:

# 提交修改
sudo docker commit -a "thefacelessman@126.com" -m "jenkins v2.235.1-lts with support for maven, docker & k8s" dao_jenkins_1 jenkins_with_dockercli:2.235.1-lts

# 中止并移除旧容器
sudo docker rm -f dao_jenkins_1

# 以新image启动新容器
sudo docker run -d -p 8081:8080 -p 50001:50000 \
    -v /data2/jenkins/jenkins_home:/var/jenkins_home \
    -v /etc/localtime:/etc/localtime:ro \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /etc/docker:/etc/docker \
    -v /usr/bin/docker:/usr/bin/docker \
    -v /usr/local/bin/helm:/bin/helm \
    --restart=always  \
    --name dao_jenkins_1 \
    jenkins_with_dockercli:2.235.1-lts

若是须要, 能够将 image push 到私有的 docker registry:

docker login --username=<your-useranme> registry.cn-hangzhou.aliyuncs.com
docker tag jenkins_with_dockercli:2.235.1-lts registry.cn-hangzhou.aliyuncs.com/faceless/jenkins_with_dockercli:2.235.1-lts
docker push registry.cn-hangzhou.aliyuncs.com/faceless/jenkins_with_dockercli:2.235.1-lts

四. 附录

参考资料:

相关文章
相关标签/搜索