一、概述
1.1、环境介绍
我们使用的是 AWS 的 EC2 来搭建我们的集群,安装方式使用 kubeadm 来进行安装,如果使用二进制安装,可以参考我相关文档。
- 系统版本:ubuntu 16.04
- k8s 版本:1.17.1
- docker 版本:18.06-ce
1.2、流程图
1.3、集群配置
名称 | 配置 | 内网IP | 外网IP |
---|---|---|---|
k8s-master | 2核4GB | 172.31.20.184 | 54.226.118.74 |
k8s-node1 | 2核4GB | 172.31.27.69 | 52.90.221.230 |
k8s-node2 | 2核4GB | 172.31.30.9 | 3.85.219.119 |
二、k8s 部署
2.1、安装 docker
安装源大家可以参照官方文档 https://docs.docker.com/install/linux/docker-ce/ubuntu/ ,我这里不再进行演示,如没有特殊说明,操作将在三台集群上面都要执行。
apt-get install docker-ce=18.06.3~ce~3-0~ubuntu
systemctl enable docker
2.2、安装 kubeadm, kubelet and kubectl
安装源文档请参考官方文档 https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm ,详细步骤我这里进行省略。
sudo apt-get update && sudo apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
2.3、安装 k8s 集群
请参考文档 https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/ ,在 master 节点运行。
kubeadm init --kubernetes-version=v1.17.1 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12
在 node 节点上运行添加集群的命令。
kubeadm join 172.31.20.184:6443 --token w3fu9a.rs8eknt079n2e8r8 \
--discovery-token-ca-cert-hash sha256:7392d6f6576b3c9ba5f78d1c54d9a0b1369f77bd498da8104a096b62c6b14c06
以后的 kubectl 都是在 master 节点上进行操作,添加 cni 插件,我们这里选择 flannel。
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml
到目前为止,我们的集群已经创建完成,参照官方文档执行,过程很简单。
root@ip-172-31-20-184:~# kubectl get no
NAME STATUS ROLES AGE VERSION
ip-172-31-20-184 Ready master 21m v1.17.1
ip-172-31-27-69 Ready <none> 16m v1.17.1
ip-172-31-30-9 Ready <none> 16m v1.17.1
三、组件安装
整个 CI/CD 过程中我们用到了很多工具,比如 gitlab,jenkins,harbor,在生产环境,建议大家把 gitlab 和 harbor 放在独立的机器上面,我这里为了简便,直接放在 k8s 集群中。
3.1、安装 helm3
请参见官方文档 https://helm.sh/docs/intro/install/ 。
wget https://get.helm.sh/helm-v3.0.2-linux-amd64.tar.gz
tar xf helm-v3.0.2-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/
chmod +x /usr/local/bin/helm
3.2、安装 gitlab
参见官方文档 https://docs.gitlab.com/charts/installation/ 。
helm repo add gitlab https://charts.gitlab.io/
后来发现 gitlab 目前还不支持 helm3,那我就选择了使用 EC2 来进行创建。
https://about.gitlab.com/install/#ubuntu?version=ce
3.3、安装 harbor
参见官方文档 https://github.com/goharbor/harbor-helm/blob/master/README.md
helm repo add harbor https://helm.goharbor.io
helm install my-release harbor/harbor
安装过程中还是出现了一些问题,是因为没有 pv,懒得去设置了,后来还是选择了单机进行安装。
参照下面文档安装 https://github.com/goharbor/harbor/blob/master/docs/installation_guide.md 。
3.4、安装 jenkins
3.4.1、优点
我们以云原生的方式,将jenkins master,jenkins slave全部部署于kubernetes之上,从而打造一个高可用,弹性伸缩的CI/CD管道。
- 推送代码到托管镜像仓库
- gitlab 基于webhook触发jenkins pipeline项目
- Jenkins master分配kubernetes slave作为项目的执行环境,同时k8s启动slave pod
- Jenkins slave pod运行pipeline中指定的任务第一步从私有代码仓库拉下代码
- Jenkins slave pod执行代码测试,测试完毕后依据代码仓库格式,构造镜像
- Jenkins slave pod推送镜像到Harbor上
- Jenkins slave pod执行应用服务的更新任务
- 应用服务pod所在节点拉取相应的镜像,完成镜像的替换,即应用的更新
- 服务高可用:当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master 容器,并且将 Volume 分配给新创建的容器,保证数据不丢失,从而达到集群服务高可用。
- 动态伸缩:合理使用资源,每次运行 Job 时,会自动创建一个 Jenkins Slave,Job 完成后,Slave 自动注销并删除容器,资源自动释放,而且 Kubernetes 会根据每个资源的使用情况,动态分配 Slave 到空闲的节点上创建,降低出现因某节点资源利用率高,还排队等待在该节点的情况。
- 扩展性好:当 Kubernetes 集群的资源严重不足而导致 Job 排队等待时,可以很容易的添加一个 Kubernetes Node 到集群中,从而实现扩展。
3.4.2、创建 nfs
因为 master 需要持久存储,我们这里就简单的选择 nfs ,我们在 master 节点上进行创建服务。
创建过程请参照文档 https://blog.csdn.net/qq_37860012/article/details/86717891 。
root@ip-172-31-20-184:/home/nfs# showmount -e 172.31.20.184
Export list for 172.31.20.184:
/home/nfs/jenkins *
master 节点目前授予权限。
chown ubuntu.ubuntu -R /home/nfs/jenkins
3.4.3、创建 nginx-ingress
参考文档 https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-manifests/
3.4.5、安装 jenkins
前面所需要的东西都已经配置好了,那我们开始安装 jenkins,请应用我下面的 yaml 文件
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jenkins
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list","watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
spec:
selector:
app: jenkins
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP
- name: agent
port: 50000
protocol: TCP
targetPort: 50000
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: jenkins.wzlinux.com
http:
paths:
- backend:
serviceName: jenkins
servicePort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 0
template:
metadata:
labels:
app: jenkins
spec:
securityContext:
fsGroup: 1000
serviceAccountName: jenkins
containers:
- name: jenkins
image: jenkins/jenkins:lts-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: web
protocol: TCP
- containerPort: 50000
name: agent
protocol: TCP
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
env:
- name: JAVA_OPTS
value: "-Xms1G -Xmx1G -XX:PermSize=512m -XX:MaxPermSize=1024m -Duser.timezone=Asia/Shanghai"
- name: TRY_UPGRADE_IF_NO_MARKER
value: "true"
volumes:
- name: jenkins-home
# hostPath:
# path: "/home/jenkins"
nfs:
server: 172.31.20.184
path: "/home/nfs/jenkins/"