赞
踩
将Jenkins的编译环境迁移至k8s中
部署私有镜像仓库(Harbor)
Harbor 是由 VMware 公司中国团队为企业用户设计的 Registry server 开源项目,包括了权限管理(RBAC)、LDAP、审计、管理界面、自我注册、HA 等企业必需的功能,同时针对中国用户的特点,设计镜像复制和中文支持等功能。
作为一个企业级私有 Registry 服务器,Harbor 提供了更好的性能和安全。提升用户使用 Registry 构建和运行环境传输镜像的效率。Harbor 支持安装在多个 Registry 节点的镜像资源复制,镜像全部保存在私有 Registry 中, 确保数据和知识产权在公司内部网络中管控。
另外,Harbor 也提供了高级的安全特性,诸如用户管理,访问控制和活动审计等:https://goharbor.io/
配置HTTPS
默认情况下,Harbor不附带证书,可以在没有安全性的情况下部署Harbor,以便您可以通过HTTP连接到它。但是,只有在没有连接到外部Internet的空白测试或开发环境中,才可以使用HTTP。在没有空隙的环境中使用HTTP会使您遭受中间人攻击;要配置HTTPS,必须创建SSL证书。
您可以使用由受信任的第三方CA签名的证书,也可以使用自签名证书。本节介绍如何使用 OpenSSL创建CA,以及如何使用CA签署服务器证书和客户端证书。
mkdir /opt/cert
cd /opt/cert
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -sha512 -days 3650 \
-subj "/C=CN/ST=ShangHai/L=ShangHai/O=Oldboy/OU=Linux/CN=192.168.12.11" \
-key ca.key \
-out ca.crt
openssl genrsa -out 192.168.12.11.key 4096
openssl req -sha512 -new \
-subj "/C=CN/ST=ShangHai/L=ShangHai/O=Oldboy/OU=Linux/CN=192.168.12.11" \
-key 192.168.12.11.key \
-out 192.168.12.11.csr
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1=yourdomain.com
DNS.2=yourdomain
DNS.3=hostname
EOF
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = IP:192.168.12.11
EOF
openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in 192.168.12.11.csr \
-out 192.168.12.11.crt
yum install yum-utils -y
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
yum -y install docker-ce
systemctl enable --now docker
颁发证书给Harbor和Docker来用
生成后ca.crt,192.168.12.70.crt和192.168.12.70.key文件,必须将它们提供给Harbor和Docker,和重新配置港使用它们
openssl x509 -inform PEM -in 192.168.12.11.crt -out 192.168.12.11.cert
mkdir -pv /etc/docker/certs.d/192.168.12.11/
cp 192.168.12.11.{cert,key} ca.crt /etc/docker/certs.d/192.168.12.11/
# 如果nginx端口默认部署443和80,后面port则指定为端口号
/etc/docker/certs.d/192.168.12.11:port
/etc/docker/certs.d/192.168.12.11:port
# 复制Harbor证书(当前测试执行此步)
mkdir -p /data/cert
cp 192.168.12.11.crt /data/cert
cp 192.168.12.11.key /data/cert
# 重启docker,加载证书
systemctl restart docker
链接:https://github.com/goharbor/harbor
# 进入下载目录
cd /opt
# 下载
wget https://github.com/goharbor/harbor/releases/download/v2.1.0-rc2/harbor-offline-installer-v2.1.0-rc2.tgz
# 解压,妈妈,
tar xf harbor-offline-installer-v2.1.0-rc2.tgz
# 进入harbor目录
cd harbor/
# 下载docker-composrt
curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 打印出上方地址,复制到浏览器下载
echo "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)"
https://github.com/docker/compose/releases/download/1.24.1/docker-compose-Linux-x86_64
# 设置可执行权限
mv docker-compose /usr/local/bin/
chmod +x /usr/local/bin/docker-compose
# 测试docker-composer
docker-compose -v
# 修改harbor.yaml以下三处
hostname: 192.168.12.11
certificate: /data/cert/192.168.12.11.crt
private_key: /data/cert/192.168.12.11.key
# 生成配置文件,其实就是导入压缩包内的镜像 #
docker load < harbor.v2.1.0.tar.gz
./prepare
# 清空相关容器
docker-compose down
# 安装并启动
./install.sh
# 耐心等待...
Creating network "harbor_harbor" with the default driver
Creating harbor-log ... done
Creating harbor-db ... done
Creating harbor-portal ... done
Creating registry ... done
Creating redis ... done
Creating registryctl ... done
Creating harbor-core ... done
Creating nginx ... done
Creating harbor-jobservice ... done
✔ ----Harbor has been installed and started successfully.----
# 若报错,则查看是否端口被占用,结束相关端口即刻,一般为nginx的80端口
# 修改端口可改为8089或其他,两处都要修改,再次执行脚本即可
vim harbor.yaml
hostname: 192.168.12.11:8089
port: 8089
# 先执行prepare,否则配置不生效
./prepare
./install.sh
访问ip测试:https://192.168.12.11:8089
用户名:admin
密码 :Harbor12345
# 测试登录
docker login 192.168.12.11 --username=admin --password=Harbor12345
# 测试打包、推送到私有仓库
[root@k8s-master1 harbor]# docker pull nginx
[root@k8s-master1 harbor]# docker tag 62d49f9bab67 192.168.12.11/test/nginx:v1
[root@k8s-master1 harbor]# docker push 192.168.12.11/test/nginx:v1
# 拉取
[root@k8s-master1 harbor]# docker pull 192.168.12.11/test/nginx:v1
# k8s集群所有节点都必须给docker做证书认证
for i in n1 n2;
do
ssh $i "mkdir -pv /etc/docker/certs.d/192.169.12.11/"
scp 192.168.12.11.cert 192.168.12.11.key ca.crt root@$i:/etc/docker/certs.d/192.168.12.11/
ssh $i "systemctl restart docker"
done
以下仅为配置举例,可用docker登录到多个私有仓库,公有仓库无需配置
172.23.0.244
为集群vip
地址,按理说可通过集群内的所有地址来访问所有服务
PS
:用时删掉中文注释,第一个为去除中文的版本
参考:Docker配置连接多个私有仓库
{
"registry-mirrors": [
"https://xj6uu5rz.mirror.aliyuncs.com",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com",
"https://docker.mirrors.ustc.edu.cn"
],
"insecure-registries": [
"harbor1.peng.cn",
"172.23.0.244:30002",
"harbor2.peng.cn",
"172.23.0.244:30003"
],
"exec-opts": ["native.cgroupdriver=systemd"],
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5,
"log-opts": {
"max-size": "300m",
"max-file": "2"
},
"live-restore": true
}
# 说明:
{
"registry-mirrors": [
"https://xj6uu5rz.mirror.aliyuncs.com", # 阿里云镜像加速器
"https://registry.docker-cn.com", # docker官方镜像加速
"http://hub-mirror.c.163.com", # 163镜像加速
"https://docker.mirrors.ustc.edu.cn" # ustc镜像加速
],
"insecure-registries": [
"registry.cn-shanghai.aliyuncs.com", # 阿里云公开(自己)的容器镜像仓库,不添加直接login也可以
"harbor1.peng.cn", # harbor1私有仓库解析:域名
"172.23.0.244:30002", # harbor1私有仓库解析:IP
"harbor2.peng.cn", # harbor2私有仓库解析:域名
"172.23.0.244:30003" # harbor2私有仓库解析:IP
],
"exec-opts": ["native.cgroupdriver=systemd"],
"max-concurrent-downloads": 10, # docker镜像分布式拉取
"max-concurrent-uploads": 5, # docker镜像分布式上传
"log-opts": {
"max-size": "300m", # docker日志最大保留大小
"max-file": "2" # docker日志最多保留个数
},
"live-restore": true # 重启docker时不重启运行中的容器
}
# 添加到/etc/hosts做解析
172.23.0.244 harbor1.peng.cn harbor2.peng.cn
# 重载docker
systemctl daemon-reload
systemctl restart docker.service
# 登录测试 harbor1.peng.cn
[root@k8s-master02 ~]# docker login harbor1.peng.cn -uadmin -pHarbor12345
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
# 登录测试 harbor2.peng.cn
[root@k8s-master02 ~]# docker login harbor2.peng.cn -uadmin -pHarbor12345
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
# 查看认证记录
[root@k8s-master02 ~]# cat /root/.docker/config.json
{
"auths": {
# 此为dockerhub共有仓库
"https://index.docker.io/v1/": {
"auth": "MTg5NTQzNTQ2NzE6MjAyMC5wZW5n"
},
"harbor1.peng.cn": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
},
"harbor2.peng.cn": {
"auth": "YWRtaW46SGFyYm9yMTIzNDU="
}
}
Harbor私有仓库运行一段时间后,仓库中存有大量镜像,会占用太多的存储空间。直接通过Harbor界面删除相关镜像,并不会自动删除存储中的文件和镜像。需要停止Harbor服务,执行垃圾回收命令,进行存储空间清理和回收。
1、首先,删除Harbor的UI中的存储库。这是软删除。您可以删除整个存储库或仅删除它的标签。软删除后,Harbour中不再管理存储库,但是存储库的文件仍然保留在Harbour的存储中。
2、接下来,使用注册表的垃圾回收(GC)删除存储库的实际文件。在执行GC之前,确保没有人推送图像或Harbour根本没有运行。如果有人在GC运行时推送镜像,则存在镜像层被错误删除的风险,从而导致镜像损坏。所以在运行GC之前,首选的方法是先停止Harbour。
# 先登录Harbor仓库web端,清空所有build镜像,再执行此脚本(切勿清理基础镜像!!!)
cd /usr/local/harbor
docker-compose stop
docker run -it --name gc --rm --volumes-from registry vmware/registry-photon:v2.6.2-v1.5.0 garbage-collect /etc/registry/config.yml
docker-compose start
# 检查可清理镜像数
# docker run -it --name gc --rm --volumes-from registry vmware/registry-photon:v2.6.2-v1.5.0 garbage-collect --dry-run /etc/registry/config.yml | wc -l
#!/bin/bash
# 先登录Harbor仓库web端,清空所有build镜像,再执行此脚本(切勿清理基础镜像!!!)
# 不符合该环境则退出脚本
CheckEnv(){
if [[ `hostname` == 'h100' ]];then
echo -e "\033[36m当前服务器: `hostname` 已指向: 测试环境\033[0m"
HOST='xxx.dev.com'
else
echo -e "\033[5;41;33m检测到脚本未在【生产/预生产】服务器上执行,已退出!\033[0m"
exit
fi
}
CheckEnv
Df1=`df -h | grep '/$' | awk '{print $5}'`
Image_num=`docker run -it --name gc --rm --volumes-from registry vmware/registry-photon:v2.6.2-v1.5.0 garbage-collect --dry-run /etc/registry/config.yml | grep "marked" | awk 'END{print $4}'`
x="————————————————————————————————————————————————————————"
clear
echo ">>>>>>>>>>>>>>>> Harbor仓库缓存清理工具 <<<<<<<<<<<<<<<<"
cd /usr/local/harbor &&\
echo "正在关闭Harbor服务..." && \
echo $x
docker-compose stop &&\
echo $x
echo "正在删除残留镜像..." &&\
docker run -it --name gc --rm --volumes-from registry vmware/registry-photon:v2.6.2-v1.5.0 garbage-collect /etc/registry/config.yml &>/dev/null &&\
echo "成功删除$Image_num个镜像!" &&\
echo $x
echo "正在启动Harbor服务..." &&\
docker-compose start &&\
echo $x
echo "Harbor服务启动成功!"
Df2=`df -h | grep '/$' | awk '{print $5}'`
echo "清理前磁盘使用占比: $Df1"
echo "清理后磁盘使用占比: $Df2"
echo $x
# 检查可清理镜像
# docker run -it --name gc --rm --volumes-from registry vmware/registry-photon:v2.6.2-v1.5.0 garbage-collect --dry-run /etc/registry/config.yml
# 若误删了Harbor的某个容器,比如nginx,导致Harbor无法访问或拉取代码失败,执行以下命令修复组件即可解决,不会重置harbor的配置
#cd /usr/local/harbor
#./install.sh
[root@h11 ~]# sh ~/scripts/clean_harbor_image.sh
>>>>>>>>>>>>>>>> Harbor仓库缓存清理工具 <<<<<<<<<<<<<<<<
正在关闭Harbor服务...
————————————————————————————————————————————————————————
Stopping nginx ... done
Stopping harbor-jobservice ... done
Stopping harbor-core ... done
Stopping registry ... done
Stopping registryctl ... done
Stopping harbor-db ... done
Stopping harbor-portal ... done
Stopping redis ... done
Stopping harbor-log ... done
————————————————————————————————————————————————————————
正在删除残留镜像...
成功删除198个镜像!
————————————————————————————————————————————————————————
正在启动Harbor服务...
Starting log ... done
Starting registry ... done
Starting registryctl ... done
Starting postgresql ... done
Starting portal ... done
Starting redis ... done
Starting core ... done
Starting jobservice ... done
Starting proxy ... done
————————————————————————————————————————————————————————
Harbor服务启动成功!
清理前磁盘使用占比: 89%
清理后磁盘使用占比: 77%
————————————————————————————————————————————————————————
最近我们构建和部署服务的方式与原来相比简直就是突飞猛进,像那种笨拙的、单一的、用于构建单体式应用程序的方式已经是过去式了。
现在的应用为了提供更好的拓展性和可维护性,都会去拆解成各种相互依赖小、解耦性强的微服务,这些服务有各自的依赖和进度。这跟我们的Kubernetes不谋而合。
我是将Harbor私有镜像仓库装在了k8s-master1上~
mkdir /opt/cert && cd /opt/cert
cat > admin-csr.json << EOF
{
"CN":"admin",
"key":{
"algo":"rsa",
"size":2048
},
"names":[
{
"C":"CN",
"L":"BeiJing",
"ST":"BeiJing",
"O":"system:masters",
"OU":"System"
}
]
}
EOF
# 下载
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
# 设置执行权限
chmod +x cfssljson_linux-amd64 cfssl_linux-amd64
# 移动到/usr/local/bin
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
mv cfssl_linux-amd64 /usr/local/bin/cfssl
cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key --profile=kubernetes admin-csr.json | cfssljson -bare admin
openssl pkcs12 -export -out ./jenkins-admin.pfx -inkey ./admin-key.pem -in ./admin.pem -passout pass:123456
系统管理 ---> 系统配置 ---> cloud
[root@k8s-master1 ~]# kubectl create secret generic kubeconfig --from-file=.kube/config
secret/kubeconfig created
pipeline {
agent {
kubernetes{
cloud "${KUBERNETES_NAME}" #集群名字
slaveConnectTimeout 1200 #连接超时时间
yaml '''
apiVersion: v1
kind: pod #metadata 流水线默认创建,此处不许设置
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:4.7-1-jdk11
args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
imagePullPolicy: IfNotPresent #镜像拉取策略:不存在则拉取
volumeMounts: #挂载时区,用一个系统时间
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- name: docker #与流水线中容器名称必须一致container(name: 'docker', shell: 'echo')
image: docker:19.03.15-git #docker容器镜像必须19版本
imagePullPolicy: IfNotPresent
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/var/run/docker.sock"
name: "volume-docker"
readOnly: false
- mountPath: "/etc/hosts"
name: "volume-hosts"
readOnly: false
- name: kubectl #与流水线中容器名称必须一致 container(name: 'kubectl', shell: 'echo')
image: bitnami/kubectl:1.20.2 #kubectl版本要与k8s本版一致
imagePullPolicy: IfNotPresent
tty: true
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/var/run/docker.sock"
name: "volume-docker"
readOnly: false
- mountPath: "/root/.kube"
name: "kubeconfig"
readOnly: false
- name: golang #业务容器
image: golang:1.16.3
imagePullPolicy: IfNotPresent
tty: true
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
command: #默认指令,不执行相当于占位符
- "cat"
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- name: maven #java所需容器镜像
image: maven:3.6.3-openjdk-8
tty: true
command:
- "cat"
volumeMounts:
- mountPath: "/etc/localtime"
name: "volume-2"
readOnly: false
- mountPath: "/root/.m2/repository"
name: "volume-maven-repo"
readOnly: false
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
volumes:
- name: volume-maven-repo
emptyDir: {}
- name: volume-2
hostPath:
path: "/usr/share/zoneinfo/Asia/Shanghai"
- name: kubeconfig
secret:
secretName: kubeconfig
items:
- key: config
path: config
- name: volume-docker
hostPath:
path: "/var/run/docker.sock"
- name: volume-hosts
hostPath:
path: /etc/hosts
'''
}
}
stages {
stage('源代码管理') {
parallel {
stage('拉取代码') {
steps {
git(url: '${GIT_REPOSITORY_URL}', branch: '${GIT_TAG}', changelog: true, credentialsId: '${CREDENTIALS_ID}')
}
}
stage('系统检查及初始化') {
steps {
sh """
echo "Check Sysyem Env"
"""
}
}
}
}
stage('编译及构建') {
parallel {
stage('编译代码') {
steps {
container(name: 'golang', shell: 'echo') {
sh """
go build main.go
"""
}
}
}
stage('初始化操作系统及kubernetes环境') {
steps {
script {
CommitID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
CommitMessage = sh(returnStdout: true, script: "git log -1 --pretty=format:'%h : %an %s'").trim()
def curDate = sh(script: "date '+%Y%m%d-%H%M%S'", returnStdout: true).trim()
TAG = curDate[0..14] + "-" + CommitID + "-master"
}
}
}
}
}
stage('构建镜像及检查kubernetes环境') {
parallel {
stage('构建镜像') {
steps {
withCredentials([usernamePassword(credentialsId: '${DOCKER_REPOSITORY_CREDENTIAL_ID}', passwordVariable: 'PASSWORD', usernameVariable: 'USERNAME')]) {
container(name: 'docker', shell: 'echo') {
sh """
docker build -t ${HARBOR_HOST}/${NAMESPACE_NAME}/${REPOSITORY_NAME}:${TAG} .
docker login ${HARBOR_HOST} --username=${USERNAME} --password=${PASSWORD}
docker push ${HARBOR_HOST}/${NAMESPACE_NAME}/${REPOSITORY_NAME}:${TAG}
"""
}
}
}
}
stage('Check Kubernetes ENV') {
steps {
container(name: 'kubectl', shell: 'echo') {
sh 'sleep 10'
}
}
}
}
}
stage('Deploy Image to Kubernetes') {
steps {
container(name: 'kubectl', shell: 'echo') {
sh 'sleep 10'
}
}
}
stage('Test Service') {
steps {
sh 'sleep 10'
}
}
stage('Send Email to Admin') {
steps {
sh 'sleep 10'
}
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。