前言
这几天在公司内网环境搭建了一套 CI
环境,大体流程是,我们开发完代码提交到 gitlab
, jenkins
触发构建器,构建出 FatJar
包,其中依赖的 Jar
包到 Maven
私服下载。构建完成之后,最后将可执行的 Jar
包部署到远程的服务器上。 由于连不上外网,内网下所有的安装部署全都是离线完成的,整个搭建的过程中遇到了很多问题 ,所以这里写篇博客来记录一下。
离线安装 Docker 环境
安装 docker
通常我们安装 Docker
环境都是在线安装,不过好在官方也提供了二进制的安装文件,具体可以看官网介绍 。我们可以直接从下载页面选择我们) 选择合适的 Docker
版本到本地,下载完成之后,我们可以拷贝到内网上的服务器。官网上有具体的安装步骤,我们可以安装官网那样安装,不过这样安装就没法使用 systemctl
来管理我们的 Docker
服务。我们可以使用如下的脚步来安装。
#!/bin/sh
usage(){
echo "Usage: $0 FILE_NAME_DOCKER_CE_TAR_GZ"
echo " $0 docker-18.09.0.tgz"
echo "Get docker-ce binary from: https://download.docker.com/linux/static/stable/x86_64/"
echo "eg: wget https://download.docker.com/linux/static/stable/x86_64/docker-18.09.0.tgz"
echo ""
}
SYSTEMDDIR=/usr/lib/systemd/system
SERVICEFILE=docker.service
DOCKERDIR=/usr/bin
DOCKERBIN=docker
SERVICENAME=docker
if [ $# -ne 1 ]; then
usage
exit 1
else
FILETARGZ="$1"
fi
if [ ! -f ${FILETARGZ} ]; then
echo "Docker binary tgz files does not exist, please check it"
echo "Get docker-ce binary from: https://download.docker.com/linux/static/stable/x86_64/"
echo "eg: wget https://download.docker.com/linux/static/stable/x86_64/docker-18.09.0.tgz"
exit 1
fi
echo "##unzip : tar xvpf ${FILETARGZ}"
tar xvpf ${FILETARGZ}
echo
echo "##binary : ${DOCKERBIN} copy to ${DOCKERDIR}"
cp -p ${DOCKERBIN}/* ${DOCKERDIR} >/dev/null 2>&1
which ${DOCKERBIN}
echo "##systemd service: ${SERVICEFILE}"
echo "##docker.service: create docker systemd file"
cat >${SYSTEMDDIR}/${SERVICEFILE} <<EOF
[Unit]
Description=Docker Application Container Engine
Documentation=http://docs.docker.com
After=network.target docker.socket
[Service]
Type=notify
EnvironmentFile=-/run/flannel/docker
WorkingDirectory=/usr/local/bin
ExecStart=/usr/bin/dockerd \
-H unix:///var/run/docker.sock \
--selinux-enabled=false \
--log-opt max-size=1g
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
echo ""
systemctl daemon-reload
echo "##Service status: ${SERVICENAME}"
systemctl status ${SERVICENAME}
echo "##Service restart: ${SERVICENAME}"
systemctl restart ${SERVICENAME}
echo "##Service status: ${SERVICENAME}"
systemctl status ${SERVICENAME}
echo "##Service enabled: ${SERVICENAME}"
systemctl enable ${SERVICENAME}
echo "## docker version"
docker version
可以将上面脚本内容保存为 install_docker.sh
脚本文件。移到到刚才下载的二进制文件压缩包(例如 docker-18.09.0.tgz
)的同级目录下,运行下面命令即可完成安装。
chmod +x install_docker.sh
./install_docker.sh docker-18.09.0.tgz
如果想要卸载,可以将下面脚本内容保存到 uninstall.sh
,赋权限执行即可。
#!/bin/sh
echo '停止docker服务'
systemctl stop docker
echo '删除docker.service...'
rm -f /usr/lib/systemd/system/docker.service
echo '删除docker文件...'
rm -rf /usr/bin/docker*
echo '重新加载配置文件'
systemctl daemon-reload
echo '卸载成功...'
安装 docker-compose
docker-compose
在GitHub上就能下载,可以点击下载链接,来下载最新的二进制文件,下载完成之后,拷贝到内网服务器。执行下面命令即可
mv docker-compose-Linux-x86_64 docker-compose
mv docker-compose /usr/local/bin/
# 验证是否安装成功
docker-compose -v
在外网环境准备镜像
docker
环境准备好之后,接下来我们需要准备 gitlab
、 jenkins
和 nexus
的镜像文件。具体操作就是我们先再外网环境将这些镜像都下载到本地,然后使用 docker save
导出镜像文件,拷贝到内网环境,然后再使用 docker load
将镜像文件导入。这里使用到的版本基本都是最新的。具体的命令如下:
# 下载镜像
docker pull gitlab/gitlab-ce:latest
docker pull jenkins/jenkins:lts
docker pull sonatype/nexus3:latest
# 导出镜像
docker save gitlab/gitlab-ce:latest > gitlab.tar
docker save jenkins/jenkins:lts > jenkins.tar
docker save sonatype/nexus3:latest > nexus3.tar
如果网速不行的话,你就得等上一会儿了,因为这些镜像的大小还是比较大的 。 gitlab
大概在 1.8G
左右。所有需要的镜像下载完成中,同样的拷贝到内网服务器。接下来使用如下命令将所有镜像都导入到本地
# 导入镜像
docker load < gitlab.tar
docker load < jenkins.tar
docker load < nexus3.tar
导入成功后,我们使用 docker images
就能查看我们本地的镜像了。
[root@CentOS7 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gitlab/gitlab-ce latest 2b9ac1a40dd1 7 days ago 1.81GB
sonatype/nexus3 latest e56a3b1f769b 9 days ago 630MB
jenkins/jenkins lts 5d1103b93f92 2 weeks ago 656MB
使用docker-compose启动镜像
我们可以一个一个单独的启动这三个应用,不过为了方便,我们可以使用 docker-compose
工具,一次将所有容器都启动起来。选择合适的目录,例如 root/ci
下,新建如下的 docker-compose.yaml
文件
version: "3.6"
services:
gitlab:
image: gitlab/gitlab-ce:latest
container_name: gitlab
ports:
- 443:443
- 80:80
- 22:22
volumes:
- /root/ci/gitlab/config:/etc/gitlab # 映射配置文件到本地
- /root/ci/gitlab/logs:/var/log/gitlab # 映射日志文件到本地
- /root/ci/gitlab/data:/var/opt/gitlab # 映射数据文件到本地
jenkins:
image: jenkins/jenkins:lts
user: root
container_name: jenkins
ports:
- 8002:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /root/ci/jenkins:/var/jenkins_home # 映射jenkins数据到本地
- /usr/bin/docker:/usr/bin/docker
nexus:
image: sonatype/nexus3:latest
container_name: nexus
user: root
ports:
- 8081:8081
volumes:
- /root/ci/nexus-data:/nexus-data # 映射nexus数据到本地
具体上面 yaml
文件里的一些参数配置,需要根据实际情况来定,例如端口的映射和数据卷的映射等。配置文件编写完成之后。我们可以直接在文件所在目录下执行 docker-compse up -d
来启动这三个容器。执行完成之后,我们可以使用 docker ps
来查看具体容器是否运行。我们也可以查看详情的应用启动日志,例如使用 docker logs -f gitlab
来查看 gitlab
启动日志。
配置Gitlab
gitlib
启动完成之后,我们还需要做一些配置,不然会有一些问题,最常见的就是新建项目之后,显示的 git
下载链接中带着容器内的主机名称。实际应该是 IP
地址或者域名。我们可以通过如下命令来修改
# 首先进入到容器内
docker exec -it gitlab bash
# 修改 /etc/gitlab/gitlab.rb 文件
vi /etc/gitlab/gitlab.rb
# 找到如下内容并作出如下的修改
external_url 'http://10.211.55.3' # 默认的站点Url配置项
# 修改完成之后,wq 保存,然后重新配置gitlab
gitlab-ctl reconfigure
reconfigure
执行完成之后,退出容器,然后执行 docker restart gitlab
重启一下。重启完成之后,我们在浏览器输入http://10.211.55.3 就能直接访问到 gitlab
了。首先我们要做的就是重置 root
账户的密码,重置完成之后,我们就可以使用 root
账户登录了。
配置 Jenkins
jenkins
容器启动之后,在容器日志中会有第一次登录需要的管理员密码,我们使用 docker logs -f jenkins
就可以看到。用初始化密码登录之后,出现的界面是插件的安装,由于我们连不上外网,所以这里可以跳过。接下来设置一个管理员用户密码,我们就进入主页了。但是插件怎么办呢,这里有两种解决办法。
- 先在外网环境按照上面
docker-compose
文件内容启动一个jenkins
容器,启动完成之安装我们需要的插件,我们也可以直接安装新手入门的推荐插件。安装完成之后,我们在系统管理 > 插件管理 > 可选插件
中搜索并安装其他我们需要的插件,例如docker
、gitlab
、SSH
和Publish Over SSH
等。由于我们将容器内jenkins_home
目录映射到了本地,所以我们直接可以从本地的目录root/ci/jenkins/
中看到plugins
插件目录。我们可以直接将此目录打包拷贝到内网服务器的同名目录。然后重启容器即可。 - 第二种方法就是下载插件的离线安装包,下载地址在 http://updates.jenkins-ci.org/download/plugins/ ,我们可以从该页面下载我们需要的插件,格式是
hpi
。下载好之后我们拷贝到内网服务器,进入jenkins
的插件安装目录。手动上传插件安装。
插件安装完成之后,我们还需要对 Jenkins
做一些配置。具体就是 JDK
和 Maven
的配置,具体配置位置在 系统管理-全局工具管理
页面下。容器内自带 JDK
,位置在 usr/local/openjdk-8
,我们可以直接填这个路径。但是容器内不带 maven
,解决方法可以是外挂一个 maven
到容器内,我们可以在 docker-compose
中 jenkins
的配置里添加一项数据卷映射,例如
jenkins:
image: jenkins/jenkins:lts
user: root
container_name: jenkins
ports:
- 8002:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /root/ci/jenkins:/var/jenkins_home # 映射jenkins数据到本地
- /root/ci/maven:/usr/local/maven # 将本地 maven 映射到容器内
- /usr/bin/docker:/usr/bin/docker
添加完成之后,我们就可以填写 maven 的地址为 /usr/local/maven
。另外 maven
的配置文件(settings
)我们还需要改成 /usr/local/maven/conf/settings
,这个配置文件具体的配置在配置完 maven
私服后再设置。 另外还有一个 Publish Over SSH
配置我们在任务测试的过程中设置。
配置 Maven 私服
nexus
容器启动完成之后,我们通过映射出来的端口就可以访问到了。默认的 admin
账户密码在 /nexus-data/admin.password
文件中,我们可以进入容器内部查看。登录成功之后,我们就可以管理我们的 Repositories
了,这里我就用的默认的库。不过如何将 Jar
上传到私服里呢,如果在外网环境,我们可以通过代理到其他的公共仓库,但是在内网环境不行。不过我们也可以以脚本的方式将本地 .m2/repository
目录下的所有包导入到私服中。具体脚本内容为
#!/bin/bash
# copy and run this script to the root of the repository directory containing files
# this script attempts to exclude uploading itself explicitly so the script name is important
# Get command line params
while getopts ":r:u:p:" opt; do
case $opt in
r) REPO_URL="$OPTARG"
;;
u) USERNAME="$OPTARG"
;;
p) PASSWORD="$OPTARG"
;;
esac
done
find . -type f -not -path './mavenimport\.sh*' -not -path '*/\.*' -not -path '*/\^archetype\-catalog\.xml*' -not -path '*/\^maven\-metadata\-local*\.xml' -not -path '*/\^maven\-metadata\-deployment*\.xml' | sed "s|^\./||" | xargs -I '{}' curl -u "$USERNAME:$PASSWORD" -X PUT -v -T {} ${REPO_URL}/{} ;
我们可以先将本地的 repository
文件压缩拷贝到内网下。然后在 repository
目录下将上面脚本内容保存到 mavenimport.sh
中,按照下面命令方式执行脚本即可
chmod +x mavenimport.sh
# -u 用户名 -p 密码 -r 要上传的仓库,这里就是默认的
./mavenimport.sh -u admin -p admin123 -r http://ip:8081/repository/maven-releases/
执行完成之后,我们在 nexus
上就能看到我们上传的本地包了。
最后,最关键的就是配置 settings
文件,下面是一份参考的配置文件,其中 server
的用户名密码, repository
中的 ip
需要配置成自己的。
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>maven-releases</id>
<username>admin</username>
<password>admin</password>
</server>
<server>
<id>maven-snapshots</id>
<username>admin</username>
<password>admin</password>
</server>
</servers>
<mirrors>
<mirror>
<id>nexus</id>
<mirrorOf>*</mirrorOf>
<name>nexus</name>
<url>http://ip:8081/repository/maven-public/</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>dev</id>
<repositories>
<repository>
<id>nexus</id>
<url>http://ip:8081/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
</settings>
我们可以按照这份配置的内容修改前面映射到 jenkins
里的 maven
配置。
任务测试
环境准备好之后,我们就可以新建一个任务来测试了。不过我们首先需要上传一个可运行的项目到 gitlab
中。项目准备好之后,我们可以在 jenkins
中新建一个自由风格的或者 maven
项目。具体的操作图太多,我就不截图了,可以看参考目录下的链接文章。