背景
- 随着互联网时代的到来,单体架构的抗压能力已经力不从心了,各项目已经向分布式方向发展。可是这会带来一个问题:
部署很麻烦
。若集群数量非常大,手动部署的话会疯的。于是各种CI流行了起来,比如GitlabRunner
,jenkins
等等。虽说搭建这两个东西都非常简单,但作为一台CI服务器的话,我们还需要安装项目的各种环境,比如部署的是java maven项目的话,还需要安装maven、jdk环境等等。于是,本人为了工作的方便,基于centos镜像构建了一个jenkins镜像,此镜像内嵌java、maven、git、docker
环境,并安装了jenkins的许多插件,如github、multijob project
等等,并且内嵌了light-blue
的样式,总而言之,它能基本满足分布式系统的CI。
一、产品实例(内嵌multijob project案例)
二、产品实例(无任何案例)
三、安装的插件
四、该jenkins镜像具有什么特性
- 包含
multijob、Extended Choice Parameter
插件 - 拥有微服务流程构建case实例,参考如下实例,达到举一反三的目的
微服务流程构建case: 在微服务架构中,我们的模块都是以服务的方式存在的,所以可能会存在互相依赖的情况, 并且所有服务都依赖的模块叫做common模块。假设我们现在要单独部署“用户服务”, 因为 在部署“用户服务”时, 肯定会执行“mvn clean package”命令,而此命令在添加需要依赖的jar 包时是会从本地仓库去找的,所以我们要先把common模块install至本地仓库。这样, “用户服务”打包时才能依赖上最新的common模块
- 内部安装了
git, jdk, maven ssh
等软件,支持日常工作部署需要。若jenkins需要将项目虚拟化(docker), 后续可以为镜像中安装docker环境。
五、如何运行jenkins镜像
- clone项目至本地
git clone https://github.com/AvengerEug/jenkins-java-backend -b jobs
- 将工作目录下的jobs.tar.gz解压到/root下(此时root目录下会多出一个jobs的文件夹)
cd jenkins-java-backend tar -zxvf jobs.tar.gz -c /root
- 拉取jenkins镜像
docker pull registry.cn-hangzhou.aliyuncs.com/avengereug/jenkins:v2
- 启动镜像 (若需要将本地的maven仓库挂载可以添加参数: -v 宿主机maven仓库repository目录:/root/.m2/repository), 启动镜像是以host的网络模式启动的,若不需要可将
--network host
删除docker run --name jenkins -it -d -v /root/jobs:/root/.jenkins/jobs --network host registry.cn-hangzhou.aliyuncs.com/avengereug/jenkins:v2
- 浏览器访问jenkins
http://ip:8050
- 使用
root/root
用户名和密码登录 - 点击start-dynamic-proxy-adapter
- 点击左侧build with parameters, 分支名改成:
jenkins-for-dynamic-proxy
- 点击构建
-
注意事项:
-
当再次重新走CI流程时,名为
local-dynamic-proxy-adapter
的job会报错,原因是端口被占用。此时可以在此job的配置的shell脚本的第一行添加如下脚本再重新run即可:ps -ef | grep dynamic-proxy-adapter | grep -v grep | awk '{print $2}' | xargs kill -9
-
若jenkins需要在本机上部署项目,则启动容器时需要指定
network
类型为host
,这样的话,容器中暴露出来的端口和宿主机的端口一致了,容器不需要再额外暴露了, 若不想使用此网络模式,run命令时可忽略--network host
参数 -
CI执行的过程中,maven会下载依赖,过程可能会久一点,有条件的朋友可以将本地maven仓库的路径挂载至容器
六、如何查看jenkins的工作目录
- 有两种方式:
- 进入容器内部, 工作路径位于:
/root/.jenkins/
- 构建镜像时的
VOLUME
指令绑定了镜像内部的/root/.jenkins/
路径,那究竟是宿主机的哪个目录与之挂在的呢?使用docker inspect + 容器id或容器名称
命令来确认, eg:docker inspect jenkins
执行此命令后,会输出结构如下的信息:
我们找到[ { "Id": "5d955a41b56325b04e04657a16c12743abc5505a76e6fe85dbc399e5b796753e", "Created": "2020-03-23T14:14:41.293507324Z", "Path": "java", "Args": [ "-jar", "jenkins.war", "--httpPort=8050" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 2430, "ExitCode": 0, "Error": "", "StartedAt": "2020-03-23T14:14:46.480503585Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:fce6824dd89f87eedc5e43e356e1b78a6143d54290c65c8c587c58507ac6b5a1", "ResolvConfPath": "/var/lib/docker/containers/5d955a41b56325b04e04657a16c12743abc5505a76e6fe85dbc399e5b796753e/resolv.conf", "HostnamePath": "/var/lib/docker/containers/5d955a41b56325b04e04657a16c12743abc5505a76e6fe85dbc399e5b796753e/hostname", "HostsPath": "/var/lib/docker/containers/5d955a41b56325b04e04657a16c12743abc5505a76e6fe85dbc399e5b796753e/hosts", "LogPath": "/var/lib/docker/containers/5d955a41b56325b04e04657a16c12743abc5505a76e6fe85dbc399e5b796753e/5d955a41b56325b04e04657a16c12743abc5505a76e6fe85dbc399e5b796753e-json.log", "Name": "/jenkins", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "docker-default", "ExecIDs": null, "HostConfig": { "Binds": [ "/home/eug/workspace/jenkins-java-backend/jobs:/root/.jenkins/jobs" ], "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "host", "PortBindings": { "8050/tcp": [ { "HostIp": "", "HostPort": "8050" } ] }, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "Capabilities": null, "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": null, "GroupAdd": null, "IpcMode": "private", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "ConsoleSize": [ 0, 0 ], "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DeviceRequests": null, "KernelMemory": 0, "KernelMemoryTCP": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": null, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/ee1a97c8f344a32c01871c0eaec54d6d556141997776ffacef8758d19cf79a83-init/diff:/var/lib/docker/overlay2/b18b12027ec179983112befb6854c14be4940706591d58ecbbba12459da48c7d/diff:/var/lib/docker/overlay2/517a2ba8b65492a8924d0c918c312652cc9d51cb3305a3a0a96fcbf3b292c7c8/diff:/var/lib/docker/overlay2/187926888df517955161b17d3d8186f8819b98de05d9ca28b97732844c265b33/diff:/var/lib/docker/overlay2/634feff375df5b2c04cad0ae627c301d683e42451145b1d922527116f2bd298b/diff:/var/lib/docker/overlay2/06b35c7aac0be64296c3055059f664061963dfff8b3b6e23327909a1b644b797/diff:/var/lib/docker/overlay2/34221b4a597dfe5117cc042a638c13a3bf15a7ca3efead221522260208ac4ebc/diff:/var/lib/docker/overlay2/b9e017f2836b4e6f738d84351a24ffb24093a9d7d8b78a434919ff3e0e141287/diff:/var/lib/docker/overlay2/e8537efad3b1af2ebfe83ecf0c255152a8a2ff82e9bd54b76b478e215ffe28e5/diff:/var/lib/docker/overlay2/3bacca5cc70365acc8d2e6329dd6f0b873de0cb946a5929672d18199e57c5f4a/diff:/var/lib/docker/overlay2/66fd1ac299fb387ae0743a938452be4a6b6612bfad0a85065faf6dde0c2fb78d/diff", "MergedDir": "/var/lib/docker/overlay2/ee1a97c8f344a32c01871c0eaec54d6d556141997776ffacef8758d19cf79a83/merged", "UpperDir": "/var/lib/docker/overlay2/ee1a97c8f344a32c01871c0eaec54d6d556141997776ffacef8758d19cf79a83/diff", "WorkDir": "/var/lib/docker/overlay2/ee1a97c8f344a32c01871c0eaec54d6d556141997776ffacef8758d19cf79a83/work" }, "Name": "overlay2" }, "Mounts": [ { "Type": "bind", "Source": "/home/eug/workspace/jenkins-java-backend/jobs", "Destination": "/root/.jenkins/jobs", "Mode": "", "RW": true, "Propagation": "rprivate" }, { "Type": "volume", "Name": "daf861dedd5ff437d1db318c329cc36258598c7fbec9a62111b1dd0be4252227", "Source": "/var/lib/docker/volumes/daf861dedd5ff437d1db318c329cc36258598c7fbec9a62111b1dd0be4252227/_data", "Destination": "/root/.jenkins", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], "Config": { "Hostname": "ubuntu", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "8050/tcp": {} }, "Tty": true, "OpenStdin": true, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/jdk/bin:/usr/local/maven/bin", "JAVA_HOME=/usr/local/jdk", "MAVEN_HOME=/usr/local/maven" ], "Cmd": null, "Image": "registry.cn-hangzhou.aliyuncs.com/avengereug/jenkins:v2", "Volumes": { "/root/.jenkins": {} }, "WorkingDir": "/root", "Entrypoint": [ "java", "-jar", "jenkins.war", "--httpPort=8050" ], "OnBuild": null, "Labels": { "MAINTAINER": "avengerEug", "org.label-schema.build-date": "20200114", "org.label-schema.license": "GPLv2", "org.label-schema.name": "CentOS Base Image", "org.label-schema.schema-version": "1.0", "org.label-schema.vendor": "CentOS", "org.opencontainers.image.created": "2020-01-14 00:00:00-08:00", "org.opencontainers.image.licenses": "GPL-2.0-only", "org.opencontainers.image.title": "CentOS Base Image", "org.opencontainers.image.vendor": "CentOS" } }, "NetworkSettings": { "Bridge": "", "SandboxID": "1c419efa93aead7739f5ff9a062c12572109badcb41cce3eb9e1187ac4075c49", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": {}, "SandboxKey": "/var/run/docker/netns/default", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "", "Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "", "IPPrefixLen": 0, "IPv6Gateway": "", "MacAddress": "", "Networks": { "host": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "648c0afff000e653fad1a5eac5d32dffdd6e6f1808a6db0eed2c999a3978e2c2", "EndpointID": "71e5f186ea3a6f7eb5ecf6e4c394fdeb48b97db5bcfb628e39a15cf474606ea4", "Gateway": "", "IPAddress": "", "IPPrefixLen": 0, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "", "DriverOpts": null } } } } ]
Mounts
节点,如下
由如上可知,宿主机的"Mounts": [ { "Type": "volume", "Name": "daf861dedd5ff437d1db318c329cc36258598c7fbec9a62111b1dd0be4252227", "Source": "/var/lib/docker/volumes/daf861dedd5ff437d1db318c329cc36258598c7fbec9a62111b1dd0be4252227/_data", "Destination": "/root/.jenkins", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ......
"/var/lib/docker/volumes/daf861dedd5ff437d1db318c329cc36258598c7fbec9a62111b1dd0be4252227/_data"
目录与容器的/root/.jenkins
目录相互挂载,而/root/.jenkins
就是jenkins的工作目录
七、构建镜像目录及路径
- Dockerfile
FROM centos LABEL MAINTAINER=avengerEug ADD apache-maven-3.3.9-bin.tar.gz /usr/local/ RUN mv /usr/local/apache-maven-3.3.9 /usr/local/maven ADD jdk-8u221-linux-x64.tar.gz /usr/local/ RUN mv /usr/local/jdk1.8.0_221 /usr/local/jdk ENV JAVA_HOME=/usr/local/jdk ENV MAVEN_HOME=/usr/local/maven ENV PATH=$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin COPY .jenkins /root/.jenkins/ COPY ./jenkins/jenkins.war /root/ RUN yum install -y git VOLUME "/root/.jenkins" RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone EXPOSE 8050 WORKDIR /root ENTRYPOINT ["java", "-jar", "jenkins.war", "--httpPort=8050"]
- 构建镜像目录
- 构建镜像命令
docker build -t jenkins:v2 .
八、项目路径
- https://github.com/AvengerEug/jenkins-java-backend
- I am a slow walker, but I never walk backwards