在容器化广泛运用的时代,Docker镜像作为新的构建产物有着众多的优点。我们希望CI/CD能够直接输出Docker镜像,使我们流水线的部署更加的方便快捷。
同时,CI/CD作为基础设施,我们也希望能够快速的部署到我们的各个环境中,因此容器化的Jenkins也成为我们的选择之一。
Jenkins
Jenkins是一个持续集成的工具,并且拥有大量实用的插件(Maven、Gradle、Git),可以对不同风格的软件进行持续集成的管理。
使用Jenkins发布博客镜像
要发布一个博客镜像需要进行以下步骤
- 拉取源码:from github
- 编译:hexo g
- 需要npm环境
- 需要hexo-cli
- 需要依赖包:npm install
- 打包镜像
- 将编译出的html打包到nginx里面
- 运行/发布镜像
使用Jenkins编译Hexo博客
- 安装并启动Jenkins
$ docker run -d \
-v /Users/Shared/jenkins_home:/var/jenkins_home \
-p 8080:8080 -p 50000:50000 \
--name jenkins jenkins/jenkins
-
配置项目
- Git插件:拉取指定项目
- Nodejs插件:自动安装nodejs和npm,可以在shell直接使用
-
触发构建
- 手动
- 定时启动cron
打包镜像
现在我们已经有了一个前端工程的构建产物-public
,我们需要直接构建出Docker镜像。
- 添加Dockerfile
FROM nginx:stable-alpine COPY public /usr/share/nginx/html EXPOSE 80 CMD ["nginx","-g","daemon off;"]
- 执行
docker build
生成镜像
Docker Outside of Docker
Build镜像要求我们在Jenkins主机(容器)上可以使用Docker:
- 在安装Jenkins的容器中再安装一个Docker,即
Docker In Docker
- 所执行的
docker
是在Jenkins容器中安装的,所以依赖的镜像等都需要重新拉取到DID中 - 最外面的Docker只能管理Jenkins,而里面的容器只能由Jenkins容器来管理
- 所执行的
- 将主机上的
docker
工具引入到Jenkins容器中,使其编译创建兄弟容器
而不是父子
- 最外面的Docker可以统一管理所有镜像
Docker进行通信控制的主要程序是/var/run/docker.sock
,因此只要将这个sock导入到容器中即可;如果需要更多的控制,可以将/var/docker
也共享到容器中。
# 启动一个新容器,将主机的docker环境挂载进去
$ docker run \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(which docker):/bin/docker
--name docker-manager -it ubuntu
# 容器内启动其他容器(兄弟容器)
root@fd83341d1e5b:/# docker run busybox echo "Hello"
Hello
安装内嵌Docker的Jenkins
$ docker run -d \
-v /Users/Shared/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(which docker):/usr/bin/docker \
-p 8080:8080 -p 50000:50000 \
--name jenkins jenkins/jenkins
本机创建一个工作目录
/Users/Shared/jenkins_home
,需要提供访问权限
绑定jenkins
和docker
的相关目录到镜像中
为什么会失败
- 容器默认使用root用户执行操作
$ docker run -it --rm ubuntu whoami root $ docker run -it --rm ubuntu whoami uid=0(root) gid=0(root) groups=0(root)
- Dockerfile:USER 可以切换工作用户
FROM ubuntu RUN whoami & id RUN groupadd -r jenkins && useradd -r -g jenkins jenkins USER jenkins RUN whoami & id CMD whoami
$ docker build -t users/jenkins -f Dockerfile-jenkins . Sending build context to Docker daemon 2.048kB Step 1/6 : FROM ubuntu ---> 74f8760a2a8b Step 2/6 : RUN whoami & id ---> Running in 7767256e7526 root uid=0(root) gid=0(root) groups=0(root) doRemoving intermediate container 7767256e7526 ---> 9574d455d2b3 Step 3/6 : RUN groupadd -r jenkins && useradd -r -g jenkins jenkins ---> Running in a54e12e8a424 dRemoving intermediate container a54e12e8a424 ---> eade256f4b1e Step 4/6 : USER jenkins ---> Running in 00e7bffa42cf Removing intermediate container 00e7bffa42cf ---> c1acfe462d20 Step 5/6 : RUN whoami & id ---> Running in b7dac9067b80 jenkins uid=999(jenkins) gid=999(jenkins) groups=999(jenkins) Removing intermediate container b7dac9067b80 ---> d27cc6c129a8 Step 6/6 : CMD whoami ---> Running in 9f4a70001504 Removing intermediate container 9f4a70001504 ---> 71deff170f16 Successfully built 71deff170f16 Successfully tagged users/jenkins:latest
-
--user
可以指定容器用户
$ docker run -it --rm users/jenkins jenkins $ docker run -it --rm --user root users/jenkins root
容器内的root用户和主机用户是一致的(部分权限被限制)
(可以开启namespace进行分隔)
jenkins镜像使用内建的jenkins用户进行操作,而这个用户是没有操作docker的权限的
为容器用户添加权限
FROM jenkins/jenkins
USER root
# Mac上访问sock需要root(0)
RUN useradd -G root jenkins
# Linux上访问sock通常是docker(999)用户(通过脚本安装)
# RUN useradd -G docker jenkins
USER jenkins
使用Vagrant搭建Linux虚拟机
因为MacOS上的Docker是运行在一个Linux虚拟机中的,会造成用户、权限、文件的混乱,因此我们使用一台Linux虚拟机作为Docker4Jenkins的宿主机。
- 使用vagrant初始化虚拟机
$ vagrant init
# 修改 Vagrantfile,配置镜像、网络
$ vagrant up
$ vagrant ssh
- 安装Docker
vagrant@vagrant-ubuntu-trusty-64:~$ curl -fsSL https://get.docker.com -o get-docker.sh
vagrant@vagrant-ubuntu-trusty-64:~$ sudo sh get-docker.sh