CI搭建:MySQL、registry、Jenkins、gogs、gitea、Drone
MySQL
以下参考:docker安装mysql
-
创建网络:
docker create network backend
为什么要创建网络?
因为这是实现docker容器互联的方式之一, 只要在同一台主机的docker容器, 都加入到同一个网络中, 容器中的服务, 就可以通过容器名称[:端口]
的方式来访问其他容器提供的服务(如:数据库服务,http服务等) -
拉取mysql镜像:
docker pull mysql:5.7.27
-
创建物理目录, 用于存储mysql的数据库/表数据(无需指定特殊权限)
# 用于存放mysql数据文件 mkdir /opt/docker/data/mysql/data # 用于存放mysql配置文件 mkdir /opt/docker/data/mysql/conf
在/opt/docker/data/mysql/conf目录下建立3个mysql配置文件
docker.cnf
,mysql.cnf
,mysqldump.cnf
docker.cnf
内容:[mysqld] skip-host-cache skip-name-resolve
mysql.cnf
内容:[mysql] default-character-set = utf8 [mysql_safe] default-character-set = utf8 [client] default-character-set = utf8 [mysqld] pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock datadir = /var/lib/mysql #log-error = /var/log/mysql/error.log # By default we only accept connections from localhost #bind-address = 127.0.0.1 # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 # 修改mysql默认字符集 init_connect = 'SET NAMES utf8' character-set-server = utf8 collation-server = utf8_unicode_ci
mysqldump.cnf
内容:[mysqldump] quick quote-names max_allowed_packet = 16M
-
启动mysql服务:
docker run -d --name=mysql57 --net=backend -p 33306:3306 -e MYSQL_ROOT_PASSWORD=root -v /var/docker/mysql/data:/var/lib/mysql -v /var/docker/mysql/conf:/etc/mysql/conf.d mysql:5.7.27
私有仓库
-
拉取镜像:
docker pull registry
-
创建物理目录,运行容器
mkdir /var/docker/registry docker run -d --name=registry -p 5000:5000 -v /var/docker/registry:/var/lib/registry registry
-
根据容器中/etc/docker/registry/config.yml,新增delete=true配置项,允许删除镜像。
version: 0.1 log: fields: service: registry storage: delete: enabled: true cache: blobdescriptor: inmemory filesystem: rootdirectory: /var/lib/registry http: addr: :5000 headers: X-Content-Type-Options: [nosniff] health: storagedriver: enabled: true interval: 10s threshold: 3
-
让docker信任私有仓库地址,修改宿主机daemon.json, 增加:
"insecure-registries":["192.168.xxx.xxx:5000"]
vi /etc/docker/daemon.json
{ "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } }, "insecure-registries":["192.168.xxx.xxx:5000"] }
-
重启docker服务
systemctl daemon-reload systemctl restart docker
-
删除镜像。如下方法删除镜像会存在问题(存疑):删除镜像后重新push相同名字的镜像,再pull这个镜像的时候会找不到manifest
-
Registry V2 不支持通过docker search 去搜索镜像。列出所有的镜像仓库:
curl -X GET http://192.168.xxx.xxx:5000/v2/_catalog
-
列出指定镜像的所有标签:
curl -X GET http://192.168.xxx.xxx:5000/v2/username/image_name/tags/list
-
需要先查到指定标签的镜像的digest (sha256校验和),再根据这个digest来删除。
-
先执行以下命令找到该镜像的digest:
curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://192.168.xxx.xxx:5000/v2/username/image_name/manifests/latest 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}'
-
执行以下命令,根据digest删除镜像:
curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://192.168.xxx.xxx:5000/v2/username/image_name/manifests/sha256:213dbd81f3015d5bb516be0c2cfe3ce73520ef0f934c334652c3118b6f3a6a02
-
这里的删除镜像只是删除了一些元数据,需要执行下面的垃圾回收才能真正地从硬盘上删除镜像数据。进入registry容器,执行garbage-collect 命令执行垃圾回收。
docker exec -it registry /bin/registry garbage-collect /etc/docker/registry/config.yml
-
jenkins
搭建:
-
拉去镜像
docker pull jenkins/jenkins
-
创建物理目录,运行容器
#jenkins需要权限 sudo mkdir /var/docker/jenkins docker run -d -p 8080:8080 -p 50000:50000 -v /var/docker/jenkins:/var/jenkins_home --name jenkins --net=backend jenkins/jenkins
-
打开浏览器配置jenkins,http://192.168.xxx.xxx:8080 (8080对应上面映射的宿主机端口)
-
查看管理员密码,cat xxxxx 复制密码输入
docker logs jenkins # 或进入jenkins容器 docker exec -it jenkins bash
-
安装推荐插件 (等待安装完成)
-
配置管理员密码,实例url配置:http://192.168.xxx.xxx:8080/
使用:
-
系统管理->插件->添加gogs、Publish over SSH插件
-
系统管理->系统设置->Publish over SSH->
表项 内容 Passphrase Linux生成密钥时填写的,没有留空 SSH Sever:hostname 主机地址 SSH Sever:username 主机登陆时的用户名 SSH Sever:Remote Directory 远程接受文件的目录 /home/user/jenkins 高级:Passphrase / Password 用户名对应的密码 注意:可以通过用户名密码或配置密钥登陆
-
新建任务
-
Gogs Webhook:Use Gogs secret(和gogs上web钩子的secret一致,或都留空)
-
源码管理:Git->Repositories:
- Repository URL:http://
- Credentials(私有仓库需要配置此项)
-
构建:Send files or execute commands over SSH:
-
Source files:基于任务的工作空间(/var/jenkins_home/workspace/任务名),不支持绝对路径。
**/*
表示任务工作目录下所有的文件和目录。 -
Remove prefix:将Source files中的目录名移除,通常留空。
例:Source files填写为
xx/a.txt
,Remove prefix填写为xx
,移除目录名xx
后,文件a.txt
被放入远程目录Remote Directory中,而不是Remote Directory/xx/
中 -
Remote directory:基于Publish over SSH设定的服务器目录,即文件被放入
服务器目录/Remote directory/
中。不支持绝对路径,远程目录不论是否存在都会创建 -
Exec command:远程服务器执行的命令。
!!注意:
docker -v
挂载文件后,查看容器中文件的相对目录得到的结果仍可能是宿主机的目录,从而导致找不到文件
-
-
关于Git LFS:任务中设置Git后,Jenkins会自动将相应git仓库clone到任务的工作空间,其中lfs文件的指针能够clone下来、lfs文件的内容不能,并可能提示
git: 'lfs' is not a git command
,需要进入Jenkins容器安装Git LFS:-
以root用户身份登陆容器:
docker exec -u 0 -it jenkins bash
-
安装Git LFS:
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash apt-get install git-lfs git lfs install
!!注意:在源码管理->Git下选用Git LFS pull after checkout,会在工作空间内
git lfs pull
下所有大文件
-
-
也可以不在任务的配置中选用Git选项,直接使用构建->Exec command在目标机器运行
git clone
(包括LFS)命令,从而跳过在Jenkins任务工作空间内拉去文件并向目标机器传输的过程
-
其他:
# 为了publish over SSH 在Jenkins容器内生成的密钥,但后来采用账号和密码登陆
jenkins@ee95a7f72b29:/$ ssh-keygen
gogs
以下参考:docker安装gogs
搭建:
-
拉取Gogs
docker pull gogs/gogs
-
创建物理目录,启动Docker容器,需要与mysql在同一network
#新建文件夹 mkdir -p /var/docker/gogs docker run -d --name=gogs --net=backend -p 10022:22 -p 10080:3000 -v /var/docker/gogs:/data gogs/gogs
-
打开浏览器配置gogs (需要http协议) http://192.168.xxx.xxx:10080 (10080对应上面映射的本地端口)
-
数据库设置
表项 内容 数据库类型 MySQL 数据库主机 mysql57:3306(mysql容器名:容器内端口) 数据库用户 root 数据库密码 root 域名 192.168.xxx.xxx SSH端口号 10022(映射到的宿主机端口) HTTP端口号 3000(容器内端口,如果为宿主机端口,重启后页面无法打开) 应用URL http://192.168.xxx.xxx:10080/ (宿主机地址:宿主机端口)
使用:
- 添加Jenkins的web钩子:http://192.168.xxx.xxx:8080/gogs-webhook/?job=lenet(Jenkins地址:端口/gogs-webhook/job=任务名)
!注意,如果测试推送无反应,可以先向仓库push一次
其他:
### 服务器上移除重复的known_hosts
user@ubuntu:~/ai-platform/test$ git push gogs master
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:KsODc/QObB3h5RsDd/ZeSIIXttkXbNScOXTfnGK7BWo.
Please contact your system administrator.
Add correct host key in /home/userroot/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /home/userroot/.ssh/known_hosts:5
remove with:
ssh-keygen -f "/home/userroot/.ssh/known_hosts" -R "[192.168.xxx.xxx]:10022"
ECDSA host key for [192.168.xxx.xxx]:10022 has changed and you have requested strict checking.
Host key verification failed.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
gitea
搭建:同gogs
-
拉取gitea
docker pull gitea/gitea
-
启动Docker容器
#新建文件夹 mkdir -p /var/docker/gitea docker run -d --privileged=true --name=gitea --net=backend -p 11022:22 -p 11080:3000 -v /var/docker/gitea:/data gitea/gitea
-
打开浏览器配置gitea (需要http协议)http://192.168.xxx.xxx:11080 (11080对应上面映射的本地端口)
-
数据库设置
表项 内容 数据库类型 MySQL 数据库主机 mysql57:3306(mysql容器名:容器内端口) 数据库用户 root 数据库密码 root 域名 192.168.xxx.xxx SSH端口号 11022(映射到的宿主机端口) HTTP端口号 3000(容器内端口,如果为宿主机端口,重启后页面无法打开) 应用URL http://192.168.xxx.xxx:10080/ (宿主机地址:宿主机端口)
使用:
- 添加Jenkins的web钩子:http://192.168.xxx.xxx:8080/gogs-webhook/?job=lenet(Jenkins地址:端口/gogs-webhook/job=任务名)
!注意,如果测试推送无反应,可以先向仓库push一次
问题:
-
git clone
gitea中仓库时出现:Cloning into 'lenet'... Gitea: Internal Server Error Get http://localhost:11080/api/internal/serv/command/2/username/lenet?mode=1&verb=git-upload-pack: dial tcp 127.0.0.1:11080: connect: connection refused fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
向/data/gitea/conf/app.ini中添加
START_SSH_SERVER = true
后,git clone http
可以但git clone ssh
有问题(已在用户设置中添加SSH密钥)Cloning into 'lenet'... git@192.168.xxx.xxx: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
具体issue详见:
简单粗暴解决:删除~/.ssh/authorized_keys后,删除gogs、gitea容器后,重启开启gitea容器后解决,可用ssh push
Drone
搭建:
-
在Gitea设置中编辑 OAuth2 应用程序,生成客户端ID和密钥
表项 内容 应用名称 drone 重定向 URI http://192.168.xxx.xxx:18080/login (地址:宿主机端口。内部网需要端口号) -
拉去镜像:
docker pull drone/drone:1 docker pull drone/agent:1
-
生成secret用于runners和Drone server的通信:
openssl rand -hex 16 4af3a6ee506d2a06273f3583224983e0
-
运行Drone容器:
docker run \ --net=backend \ --volume=/var/docker/drone:/data \ --env=DRONE_AGENTS_ENABLED=true \ --env=DRONE_GITEA_SERVER=http://192.168.xxx.xxx:11080 \ --env=DRONE_GITEA_CLIENT_ID=Gitea生成的客户端ID \ --env=DRONE_GITEA_CLIENT_SECRET=Gitea生成的客户端密钥 \ --env=DRONE_RPC_SECRET=4af3a6ee506d2a06273f3583224983e0 \ --env=DRONE_SERVER_HOST=192.168.xxx.xxx:18080 \ --env=DRONE_SERVER_PROTO=http \ --publish=18080:80 \ --publish=10443:443 \ --detach=true \ --name=drone \ drone/drone:1
注意:
-
协议填https无法访问(需要nignx)
-
存疑:DRONE_GITEA_SERVER=http://gitea:3000 无法访问
-
与Gitea的重定向URL一致:DRONE_SERVER_HOST=192.168.xxx.xxx:18080 需要填端口号,否则识别为非法地址
-
参考:
-
-
运行Drone agent容器:
docker run -d \ --net=backend \ -v /var/run/docker.sock:/var/run/docker.sock \ -e DRONE_RPC_PROTO=http \ -e DRONE_RPC_HOST=192.168.xxx.xxx:18080 \ -e DRONE_RPC_SECRET=4af3a6ee506d2a06273f3583224983e0 \ -e DRONE_RUNNER_CAPACITY=2 \ -p 13000:3000 \ --name runner \ drone/agent:1
使用:
-
进入drone http://192.168.xxx.xxx:18080 。激活仓库后,由于报错.drone.yml格式文件无法识别,在设置中更改 main->configuration 为 .drone.yaml,然后在gitea中向仓库中增加 .drone.yaml 文件
-
drone从私有仓库pull镜像:
steps: - name: tensorflow image: 192.168.xxx.xxx:5000/username/image_name commands: - pwd
可能需要secret
参考
- docker安装mysql
- centos7 Docker私有仓库搭建及删除镜像
- Jenkins配置Publish Over SSH讲解说明
- 解决SSH: Transferred 0 file(s)
- docker安装gogs
- Gitea安装教程,本地部署时问题合集
- Incorrect permission of .ssh/ #458
- Git operations over ssh gives “Gitea: Internal error” and “Failed to get repository: dial tcp 127.0.0.1:3306: connect: connection refused” #4092
- 【官方】Drone Document/Installation/Providers/Gitea
- Drone auth not working with internal users #6883