K8S全稱是Kubernetes,是一個全新的基於容器技術的分佈式架構領先方案,基於容器技術,目的是實現資源管理的自動化,以及跨多個數據中心的資源利用率的最大化。java
若是咱們的系統設計遵循了kubernetes的設計思想,那麼傳統系統架構中那些和業務沒有多大關係的底層代碼或功能模塊,均可以使用K8S來管理,咱們沒必要再費心於負載均衡的選型和部署實施問題,沒必要再考慮引入或本身開發一個複雜的服務治理框架,沒必要再頭疼與服務監控和故障處理模塊的開發。總之,使用kubernetes提供的解決方案,會大大減小開發成本,同時能夠將精力更加集中於業務自己,並且因爲kubernetes提供了強大的自動化機制,因此係統後期的運維難度和運維成本大幅下降。node
Docker 這個新興的容器化技術當前已經被不少公司所採用,其從單機走向集羣已成必然,而云計算的蓬勃發展正在加速這一進程。Kubernetes 做爲當前惟一被業界普遍承認和看好的 Docker 分佈式系統解決方案。能夠預見,在將來幾年內,會有大量的新系統選擇它,無論是運行在企業本地服務器上仍是被託管到公有云上。linux
使用Kubernetes就是在全面部署微服務架構。微服務架構的核心就是將一個巨大的單體應用分解爲不少小的互相鏈接的微服務,一個微服務背後可能有多個實例副本在支撐,副本的數量可能會隨着系統的負荷變化而進行調整,內嵌的負載均衡器在 k8s 平臺中有多個實例副本在支撐,副本的數量可能會隨着系統的負荷變化而進行調整,內嵌的負載均衡器 在k8s 平臺中發揮了重要的做用。微服務架構使得每一個服務均可以由專門的開發團隊來開發,開發者能夠自由選擇開發技術,這對於大規模團隊來講頗有價值。另外,每一個微服務獨立開發、升級、擴展,使得系統具有很高的穩定性和快速迭代進化能力。nginx
整套環境的搭建包含:Docker環境的搭建、docker-compose環境的搭建、K8S集羣的搭建、GitLab代碼倉庫的搭建、SVN倉庫的搭建、Jenkins自動化部署環境的搭建、Harbor私有倉庫的搭建。git
本文檔中,整套環境的搭建包括:github
IP | 主機名 | 節點 | 操做系統 |
---|---|---|---|
192.168.0.10 | test10 | K8S Master | CentOS 8.0.1905 |
192.168.0.11 | test11 | K8S Worker | CentOS 8.0.1905 |
192.168.0.12 | test12 | K8S Worker | CentOS 8.0.1905 |
軟件名稱 | 軟件版本 | 說明 |
---|---|---|
Docker | 19.03.8 | 提供容器環境 |
docker-compose | 1.25.5 | 定義和運行由多個容器組成的應用 |
K8S | 1.18.2 | 是一個開源的,用於管理雲平臺中多個主機上的容器化的應用,Kubernetes的目標是讓部署容器化的應用簡單而且高效(powerful),Kubernetes提供了應用部署,規劃,更新,維護的一種機制。 |
GitLab | 12.1.6 | 代碼倉庫 |
Harbor | 1.10.2 | 私有鏡像倉庫 |
Jenkins | 2.222.3 | 持續集成交付 |
Docker 是一個開源的應用容器引擎,基於 Go 語言 並聽從 Apache2.0 協議開源。web
Docker 可讓開發者打包他們的應用以及依賴包到一個輕量級、可移植的容器中,而後發佈到任何流行的 Linux 機器上,也能夠實現虛擬化。redis
本文檔基於Docker 19.03.8 版本搭建Docker環境。spring
在全部服務器上建立install_docker.sh腳本,腳本內容以下所示。sql
#使用阿里雲鏡像中心 export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com #安裝yum工具 dnf install yum* #安裝docker環境 yum install -y yum-utils device-mapper-persistent-data lvm2 #配置Docker的yum源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #安裝容器插件 dnf install https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.13-3.1.el7.x86_64.rpm #指定安裝docker 19.03.8版本 yum install -y docker-ce-19.03.8 docker-ce-cli-19.03.8 #設置Docker開機啓動 systemctl enable docker.service #啓動Docker systemctl start docker.service #查看Docker版本 docker version
在每臺服務器上爲install_docker.sh腳本賦予可執行權限,並執行腳本,以下所示。
# 賦予install_docker.sh腳本可執行權限 chmod a+x ./install_docker.sh # 執行install_docker.sh腳本 ./install_docker.sh
Compose 是用於定義和運行多容器 Docker 應用程序的工具。經過 Compose,您可使用 YML 文件來配置應用程序須要的全部服務。而後,使用一個命令,就能夠從 YML 文件配置中建立並啓動全部服務。
注意:在每臺服務器上安裝docker-compose
#下載並安裝docker-compose curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
#賦予docker-compose可執行權限 chmod a+x /usr/local/bin/docker-compose
#查看docker-compose版本 [root@binghe ~]# docker-compose version docker-compose version 1.25.5, build 8a1c60f6 docker-py version: 4.1.0 CPython version: 3.7.5 OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
Kubernetes是一個開源的,用於管理雲平臺中多個主機上的容器化的應用,Kubernetes的目標是讓部署容器化的應用簡單而且高效(powerful),Kubernetes提供了應用部署,規劃,更新,維護的一種機制。
本文檔基於K8S 1.8.12版原本搭建K8S集羣
在全部服務器上建立install_k8s.sh腳本文件,腳本文件的內容以下所示。
#################配置阿里雲鏡像加速器開始######################## mkdir -p /etc/docker tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://zz3sblpi.mirror.aliyuncs.com"] } EOF systemctl daemon-reload systemctl restart docker ######################配置阿里雲鏡像加速器結束######################### #安裝nfs-utils yum install -y nfs-utils #安裝wget軟件下載命令 yum install -y wget #啓動nfs-server systemctl start nfs-server #配置nfs-server開機自啓動 systemctl enable nfs-server #關閉防火牆 systemctl stop firewalld #取消防火牆開機自啓動 systemctl disable firewalld #關閉SeLinux setenforce 0 sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config # 關閉 swap swapoff -a yes | cp /etc/fstab /etc/fstab_bak cat /etc/fstab_bak |grep -v swap > /etc/fstab ############################修改 /etc/sysctl.conf開始########################### # 若是有配置,則修改 sed -i "s#^net.ipv4.ip_forward.*#net.ipv4.ip_forward=1#g" /etc/sysctl.conf sed -i "s#^net.bridge.bridge-nf-call-ip6tables.*#net.bridge.bridge-nf-call-ip6tables=1#g" /etc/sysctl.conf sed -i "s#^net.bridge.bridge-nf-call-iptables.*#net.bridge.bridge-nf-call-iptables=1#g" /etc/sysctl.conf sed -i "s#^net.ipv6.conf.all.disable_ipv6.*#net.ipv6.conf.all.disable_ipv6=1#g" /etc/sysctl.conf sed -i "s#^net.ipv6.conf.default.disable_ipv6.*#net.ipv6.conf.default.disable_ipv6=1#g" /etc/sysctl.conf sed -i "s#^net.ipv6.conf.lo.disable_ipv6.*#net.ipv6.conf.lo.disable_ipv6=1#g" /etc/sysctl.conf sed -i "s#^net.ipv6.conf.all.forwarding.*#net.ipv6.conf.all.forwarding=1#g" /etc/sysctl.conf # 可能沒有,追加 echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf echo "net.ipv6.conf.lo.disable_ipv6 = 1" >> /etc/sysctl.conf echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf ############################修改 /etc/sysctl.conf結束########################### # 執行命令使修改後的/etc/sysctl.conf文件生效 sysctl -p ################# 配置K8S的yum源開始############################# cat <<EOF > /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg EOF ################# 配置K8S的yum源結束############################# # 卸載舊版本K8S yum remove -y kubelet kubeadm kubectl # 安裝kubelet、kubeadm、kubectl,這裏我安裝的是1.18.2版本,你也能夠安裝1.17.2版本 yum install -y kubelet-1.18.2 kubeadm-1.18.2 kubectl-1.18.2 # 修改docker Cgroup Driver爲systemd # # 將/usr/lib/systemd/system/docker.service文件中的這一行 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock # # 修改成 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd # 若是不修改,在添加 worker 節點時可能會碰到以下錯誤 # [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". # Please follow the guide at https://kubernetes.io/docs/setup/cri/ sed -i "s#^ExecStart=/usr/bin/dockerd.*#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd#g" /usr/lib/systemd/system/docker.service # 設置 docker 鏡像,提升 docker 鏡像下載速度和穩定性 # 若是訪問 https://hub.docker.io 速度很是穩定,也能夠跳過這個步驟,通常不需配置 # curl -sSL https://kuboard.cn/install-script/set_mirror.sh | sh -s ${REGISTRY_MIRROR} # 從新加載配置文件 systemctl daemon-reload #重啓 docker systemctl restart docker # 將kubelet設置爲開機啓動並啓動kubelet systemctl enable kubelet && systemctl start kubelet # 查看docker版本 docker version
在每臺服務器上爲install_k8s.sh腳本賦予可執行權限,並執行腳本
# 賦予install_k8s.sh腳本可執行權限 chmod a+x ./install_k8s.sh # 運行install_k8s.sh腳本 ./install_k8s.sh
只在test10服務器上執行的操做。
1.初始化Master節點的網絡環境
注意:下面的命令須要在命令行手動執行。
# 只在 master 節點執行 # export 命令只在當前 shell 會話中有效,開啓新的 shell 窗口後,若是要繼續安裝過程,請從新執行此處的 export 命令 export MASTER_IP=192.168.0.10 # 替換 k8s.master 爲 您想要的 dnsName export APISERVER_NAME=k8s.master # Kubernetes 容器組所在的網段,該網段安裝完成後,由 kubernetes 建立,事先並不存在於物理網絡中 export POD_SUBNET=172.18.0.1/16 echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts
2.初始化Master節點
在test10服務器上建立init_master.sh腳本文件,文件內容以下所示。
#!/bin/bash # 腳本出錯時終止執行 set -e if [ ${#POD_SUBNET} -eq 0 ] || [ ${#APISERVER_NAME} -eq 0 ]; then echo -e "\033[31;1m請確保您已經設置了環境變量 POD_SUBNET 和 APISERVER_NAME \033[0m" echo 當前POD_SUBNET=$POD_SUBNET echo 當前APISERVER_NAME=$APISERVER_NAME exit 1 fi # 查看完整配置選項 https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2 rm -f ./kubeadm-config.yaml cat <<EOF > ./kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration kubernetesVersion: v1.18.2 imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers controlPlaneEndpoint: "${APISERVER_NAME}:6443" networking: serviceSubnet: "10.96.0.0/16" podSubnet: "${POD_SUBNET}" dnsDomain: "cluster.local" EOF # kubeadm init # 初始化kebeadm kubeadm init --config=kubeadm-config.yaml --upload-certs # 配置 kubectl rm -rf /root/.kube/ mkdir /root/.kube/ cp -i /etc/kubernetes/admin.conf /root/.kube/config # 安裝 calico 網絡插件 # 參考文檔 https://docs.projectcalico.org/v3.13/getting-started/kubernetes/self-managed-onprem/onpremises echo "安裝calico-3.13.1" rm -f calico-3.13.1.yaml wget https://kuboard.cn/install-script/calico/calico-3.13.1.yaml kubectl apply -f calico-3.13.1.yaml
賦予init_master.sh腳本文件可執行權限並執行腳本。
# 賦予init_master.sh文件可執行權限 chmod a+x ./init_master.sh # 運行init_master.sh腳本 ./init_master.sh
3.查看Master節點的初始化結果
(1)確保全部容器組處於Running狀態
# 執行以下命令,等待 3-10 分鐘,直到全部的容器組處於 Running 狀態 watch kubectl get pod -n kube-system -o wide
具體執行以下所示。
[root@test10 ~]# watch kubectl get pod -n kube-system -o wide Every 2.0s: kubectl get pod -n kube-system -o wide test10: Sun May 10 11:01:32 2020 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES calico-kube-controllers-5b8b769fcd-5dtlp 1/1 Running 0 118s 172.18.203.66 test10 <none> <none> calico-node-fnv8g 1/1 Running 0 118s 192.168.0.10 test10 <none> <none> coredns-546565776c-27t7h 1/1 Running 0 2m1s 172.18.203.67 test10 <none> <none> coredns-546565776c-hjb8z 1/1 Running 0 2m1s 172.18.203.65 test10 <none> <none> etcd-test10 1/1 Running 0 2m7s 192.168.0.10 test10 <none> <none> kube-apiserver-test10 1/1 Running 0 2m7s 192.168.0.10 test10 <none> <none> kube-controller-manager-test10 1/1 Running 0 2m7s 192.168.0.10 test10 <none> <none> kube-proxy-dvgsr 1/1 Running 0 2m1s 192.168.0.10 test10 <none> <none> kube-scheduler-test10 1/1 Running 0 2m7s 192.168.0.10 test10 <none> <none>
(2) 查看 Master 節點初始化結果
# 查看Master節點的初始化結果 kubectl get nodes -o wide
具體執行以下所示。
[root@test10 ~]# kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME test10 Ready master 3m28s v1.18.2 192.168.0.10 <none> CentOS Linux 8 (Core) 4.18.0-80.el8.x86_64 docker://19.3.8
1.獲取join命令參數
在Master節點(test10服務器)上執行以下命令獲取join命令參數。
kubeadm token create --print-join-command
具體執行以下所示。
[root@test10 ~]# kubeadm token create --print-join-command W0510 11:04:34.828126 56132 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io] kubeadm join k8s.master:6443 --token 8nblts.62xytoqufwsqzko2 --discovery-token-ca-cert-hash sha256:1717cc3e34f6a56b642b5751796530e367aa73f4113d09994ac3455e33047c0d
其中,有以下一行輸出。
kubeadm join k8s.master:6443 --token 8nblts.62xytoqufwsqzko2 --discovery-token-ca-cert-hash sha256:1717cc3e34f6a56b642b5751796530e367aa73f4113d09994ac3455e33047c0d
這行代碼就是獲取到的join命令。
注意:join命令中的token的有效時間爲 2 個小時,2小時內,可使用此 token 初始化任意數量的 worker 節點。
2.初始化Worker節點
針對全部的 worker 節點執行,在這裏,就是在test11服務器和test12服務器上執行。
在命令分別手動執行以下命令。
# 只在 worker 節點執行 # 192.168.0.10 爲 master 節點的內網 IP export MASTER_IP=192.168.0.10 # 替換 k8s.master 爲初始化 master 節點時所使用的 APISERVER_NAME export APISERVER_NAME=k8s.master echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts # 替換爲 master 節點上 kubeadm token create 命令輸出的join kubeadm join k8s.master:6443 --token 8nblts.62xytoqufwsqzko2 --discovery-token-ca-cert-hash sha256:1717cc3e34f6a56b642b5751796530e367aa73f4113d09994ac3455e33047c0d
具體執行以下所示。
[root@test11 ~]# export MASTER_IP=192.168.0.10 [root@test11 ~]# export APISERVER_NAME=k8s.master [root@test11 ~]# echo "${MASTER_IP} ${APISERVER_NAME}" >> /etc/hosts [root@test11 ~]# kubeadm join k8s.master:6443 --token 8nblts.62xytoqufwsqzko2 --discovery-token-ca-cert-hash sha256:1717cc3e34f6a56b642b5751796530e367aa73f4113d09994ac3455e33047c0d W0510 11:08:27.709263 42795 join.go:346] [preflight] WARNING: JoinControlPane.controlPlane settings will be ignored when control-plane flag is not set. [preflight] Running pre-flight checks [WARNING FileExisting-tc]: tc not found in system path [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.18" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
根據輸出結果能夠看出,Worker節點加入了K8S集羣。
注意:kubeadm join…就是master 節點上 kubeadm token create 命令輸出的join。
3.查看初始化結果
在Master節點(test10服務器)執行以下命令查看初始化結果。
kubectl get nodes -o wide
具體執行以下所示。
[root@test10 ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION test10 Ready master 20m v1.18.2 test11 Ready <none> 2m46s v1.18.2 test12 Ready <none> 2m46s v1.18.2
注意:kubectl get nodes命令後面加上-o wide參數能夠輸出更多的信息。
Master 節點的 IP 地址發生變化,致使 worker 節點不能啓動。須要從新安裝K8S集羣,並確保全部節點都有固定的內網 IP 地址。
重啓服務器後使用以下命令查看Pod的運行狀態。
#查看全部pod的運行狀況 kubectl get pods --all-namespaces
發現不少 Pod 不在 Running 狀態,此時,須要使用以下命令刪除運行不正常的Pod。
kubectl delete pod <pod-name> -n <pod-namespece>
注意:若是Pod 是使用 Deployment、StatefulSet 等控制器建立的,K8S 將建立新的 Pod 做爲替代,從新啓動的 Pod 一般可以正常工做。
其中,pod-name表示運行在K8S中的pod的名稱,pod-namespece表示命名空間。例如,須要刪除pod名稱爲pod-test,命名空間爲pod-test-namespace的pod,可使用下面的命令。
kubectl delete pod pod-test -n pod-test-namespace
做爲反向代理將外部流量導入集羣內部,將 Kubernetes 內部的 Service 暴露給外部,在 Ingress 對象中經過域名匹配 Service,這樣就能夠直接經過域名訪問到集羣內部的服務了。相對於 traefik 來講,nginx-ingress 性能更加優秀。
注意:在Master節點(test10服務器上執行)
建立ingress-nginx-namespace.yaml文件,主要的做用是建立ingress-nginx命名空間,文件內容以下所示。
apiVersion: v1 kind: Namespace metadata: name: ingress-nginx labels: name: ingress-nginx
執行以下命令建立ingress-nginx命名空間。
kubectl apply -f ingress-nginx-namespace.yaml
建立ingress-nginx-mandatory.yaml文件,主要的做用是安裝ingress-nginx。文件內容以下所示。
apiVersion: v1 kind: Namespace metadata: name: ingress-nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: default-http-backend labels: app.kubernetes.io/name: default-http-backend app.kubernetes.io/part-of: ingress-nginx namespace: ingress-nginx spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: default-http-backend app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: default-http-backend app.kubernetes.io/part-of: ingress-nginx spec: terminationGracePeriodSeconds: 60 containers: - name: default-http-backend # Any image is permissible as long as: # 1. It serves a 404 page at / # 2. It serves 200 on a /healthz endpoint image: registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/defaultbackend-amd64:1.5 livenessProbe: httpGet: path: /healthz port: 8080 scheme: HTTP initialDelaySeconds: 30 timeoutSeconds: 5 ports: - containerPort: 8080 resources: limits: cpu: 10m memory: 20Mi requests: cpu: 10m memory: 20Mi --- apiVersion: v1 kind: Service metadata: name: default-http-backend namespace: ingress-nginx labels: app.kubernetes.io/name: default-http-backend app.kubernetes.io/part-of: ingress-nginx spec: ports: - port: 80 targetPort: 8080 selector: app.kubernetes.io/name: default-http-backend app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: nginx-configuration namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: tcp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: udp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress-serviceaccount namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: nginx-ingress-clusterrole labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - endpoints - nodes - pods - secrets verbs: - list - watch - apiGroups: - "" resources: - nodes verbs: - get - apiGroups: - "" resources: - services verbs: - get - list - watch - apiGroups: - "extensions" resources: - ingresses verbs: - get - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - apiGroups: - "extensions" resources: - ingresses/status verbs: - update --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: Role metadata: name: nginx-ingress-role namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx rules: - apiGroups: - "" resources: - configmaps - pods - secrets - namespaces verbs: - get - apiGroups: - "" resources: - configmaps resourceNames: # Defaults to "<election-id>-<ingress-class>" # Here: "<ingress-controller-leader>-<nginx>" # This has to be adapted if you change either parameter # when launching the nginx-ingress-controller. - "ingress-controller-leader-nginx" verbs: - get - update - apiGroups: - "" resources: - configmaps verbs: - create - apiGroups: - "" resources: - endpoints verbs: - get --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: RoleBinding metadata: name: nginx-ingress-role-nisa-binding namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: nginx-ingress-role subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: nginx-ingress-clusterrole-nisa-binding labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: nginx-ingress-clusterrole subjects: - kind: ServiceAccount name: nginx-ingress-serviceaccount namespace: ingress-nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-ingress-controller namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx annotations: prometheus.io/port: "10254" prometheus.io/scrape: "true" spec: serviceAccountName: nginx-ingress-serviceaccount containers: - name: nginx-ingress-controller image: registry.cn-qingdao.aliyuncs.com/kubernetes_xingej/nginx-ingress-controller:0.20.0 args: - /nginx-ingress-controller - --default-backend-service=$(POD_NAMESPACE)/default-http-backend - --configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --publish-service=$(POD_NAMESPACE)/ingress-nginx - --annotations-prefix=nginx.ingress.kubernetes.io securityContext: capabilities: drop: - ALL add: - NET_BIND_SERVICE # www-data -> 33 runAsUser: 33 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace ports: - name: http containerPort: 80 - name: https containerPort: 443 livenessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP initialDelaySeconds: 10 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 readinessProbe: failureThreshold: 3 httpGet: path: /healthz port: 10254 scheme: HTTP periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1 ---
執行以下命令安裝ingress controller。
kubectl apply -f ingress-nginx-mandatory.yaml
主要是用來用於暴露pod:nginx-ingress-controller。
建立service-nodeport.yaml文件,文件內容以下所示。
apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP nodePort: 30080 - name: https port: 443 targetPort: 443 protocol: TCP nodePort: 30443 selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx
執行以下命令安裝。
kubectl apply -f service-nodeport.yaml
查看ingress-nginx命名空間的部署狀況,以下所示。
[root@test10 k8s]# kubectl get pod -n ingress-nginx NAME READY STATUS RESTARTS AGE default-http-backend-796ddcd9b-vfmgn 1/1 Running 1 10h nginx-ingress-controller-58985cc996-87754 1/1 Running 2 10h
在命令行服務器命令行輸入以下命令查看ingress-nginx的端口映射狀況。
kubectl get svc -n ingress-nginx
具體以下所示。
[root@test10 k8s]# kubectl get svc -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default-http-backend ClusterIP 10.96.247.2 <none> 80/TCP 7m3s ingress-nginx NodePort 10.96.40.6 <none> 80:30080/TCP,443:30443/TCP 4m35s
因此,能夠經過Master節點(test10服務器)的IP地址和30080端口號來訪問ingress-nginx,以下所示。
[root@test10 k8s]# curl 192.168.0.10:30080 default backend - 404
也能夠在瀏覽器打開http://192.168.0.10:30080 來訪問ingress-nginx,以下所示。
GitLab是由GitLabInc.開發,使用MIT許可證的基於網絡的Git倉庫管理工具,且具備Wiki和issue跟蹤功能。使用Git做爲代碼管理工具,並在此基礎上搭建起來的web服務。
注意:在Master節點(test10服務器上執行)
建立k8s-ops-namespace.yaml文件,主要做用是建立k8s-ops命名空間。文件內容以下所示。
apiVersion: v1 kind: Namespace metadata: name: k8s-ops labels: name: k8s-ops
執行以下命令建立命名空間。
kubectl apply -f k8s-ops-namespace.yaml
建立gitlab-redis.yaml文件,文件的內容以下所示。
apiVersion: apps/v1 kind: Deployment metadata: name: redis namespace: k8s-ops labels: name: redis spec: selector: matchLabels: name: redis template: metadata: name: redis labels: name: redis spec: containers: - name: redis image: sameersbn/redis imagePullPolicy: IfNotPresent ports: - name: redis containerPort: 6379 volumeMounts: - mountPath: /var/lib/redis name: data livenessProbe: exec: command: - redis-cli - ping initialDelaySeconds: 30 timeoutSeconds: 5 readinessProbe: exec: command: - redis-cli - ping initialDelaySeconds: 10 timeoutSeconds: 5 volumes: - name: data hostPath: path: /data1/docker/xinsrv/redis --- apiVersion: v1 kind: Service metadata: name: redis namespace: k8s-ops labels: name: redis spec: ports: - name: redis port: 6379 targetPort: redis selector: name: redis
首先,在命令行執行以下命令建立/data1/docker/xinsrv/redis目錄。
mkdir -p /data1/docker/xinsrv/redis
執行以下命令安裝gitlab-redis。
kubectl apply -f gitlab-redis.yaml
建立gitlab-postgresql.yaml,文件內容以下所示。
apiVersion: apps/v1 kind: Deployment metadata: name: postgresql namespace: k8s-ops labels: name: postgresql spec: selector: matchLabels: name: postgresql template: metadata: name: postgresql labels: name: postgresql spec: containers: - name: postgresql image: sameersbn/postgresql imagePullPolicy: IfNotPresent env: - name: DB_USER value: gitlab - name: DB_PASS value: passw0rd - name: DB_NAME value: gitlab_production - name: DB_EXTENSION value: pg_trgm ports: - name: postgres containerPort: 5432 volumeMounts: - mountPath: /var/lib/postgresql name: data livenessProbe: exec: command: - pg_isready - -h - localhost - -U - postgres initialDelaySeconds: 30 timeoutSeconds: 5 readinessProbe: exec: command: - pg_isready - -h - localhost - -U - postgres initialDelaySeconds: 5 timeoutSeconds: 1 volumes: - name: data hostPath: path: /data1/docker/xinsrv/postgresql --- apiVersion: v1 kind: Service metadata: name: postgresql namespace: k8s-ops labels: name: postgresql spec: ports: - name: postgres port: 5432 targetPort: postgres selector: name: postgresql
首先,執行以下命令建立/data1/docker/xinsrv/postgresql目錄。
mkdir -p /data1/docker/xinsrv/postgresql
接下來,安裝gitlab-postgresql,以下所示。
kubectl apply -f gitlab-postgresql.yaml
(1)配置用戶名和密碼
首先,在命令行使用base64編碼爲用戶名和密碼進行轉碼,本示例中,使用的用戶名爲admin,密碼爲admin.1231
轉碼狀況以下所示。
[root@test10 k8s]# echo -n 'admin' | base64 YWRtaW4= [root@test10 k8s]# echo -n 'admin.1231' | base64 YWRtaW4uMTIzMQ==
轉碼後的用戶名爲:YWRtaW4= 密碼爲:YWRtaW4uMTIzMQ==
也能夠對base64編碼後的字符串解碼,例如,對密碼字符串解碼,以下所示。
[root@test10 k8s]# echo 'YWRtaW4uMTIzMQ==' | base64 --decode admin.1231
接下來,建立secret-gitlab.yaml文件,主要是用戶來配置GitLab的用戶名和密碼,文件內容以下所示。
apiVersion: v1 kind: Secret metadata: namespace: k8s-ops name: git-user-pass type: Opaque data: username: YWRtaW4= password: YWRtaW4uMTIzMQ==
執行配置文件的內容,以下所示。
kubectl create -f ./secret-gitlab.yaml
(2)安裝GitLab
建立gitlab.yaml文件,文件的內容以下所示。
apiVersion: apps/v1 kind: Deployment metadata: name: gitlab namespace: k8s-ops labels: name: gitlab spec: selector: matchLabels: name: gitlab template: metadata: name: gitlab labels: name: gitlab spec: containers: - name: gitlab image: sameersbn/gitlab:12.1.6 imagePullPolicy: IfNotPresent env: - name: TZ value: Asia/Shanghai - name: GITLAB_TIMEZONE value: Beijing - name: GITLAB_SECRETS_DB_KEY_BASE value: long-and-random-alpha-numeric-string - name: GITLAB_SECRETS_SECRET_KEY_BASE value: long-and-random-alpha-numeric-string - name: GITLAB_SECRETS_OTP_KEY_BASE value: long-and-random-alpha-numeric-string - name: GITLAB_ROOT_PASSWORD valueFrom: secretKeyRef: name: git-user-pass key: password - name: GITLAB_ROOT_EMAIL value: 12345678@qq.com - name: GITLAB_HOST value: gitlab.binghe.com - name: GITLAB_PORT value: "80" - name: GITLAB_SSH_PORT value: "30022" - name: GITLAB_NOTIFY_ON_BROKEN_BUILDS value: "true" - name: GITLAB_NOTIFY_PUSHER value: "false" - name: GITLAB_BACKUP_SCHEDULE value: daily - name: GITLAB_BACKUP_TIME value: 01:00 - name: DB_TYPE value: postgres - name: DB_HOST value: postgresql - name: DB_PORT value: "5432" - name: DB_USER value: gitlab - name: DB_PASS value: passw0rd - name: DB_NAME value: gitlab_production - name: REDIS_HOST value: redis - name: REDIS_PORT value: "6379" ports: - name: http containerPort: 80 - name: ssh containerPort: 22 volumeMounts: - mountPath: /home/git/data name: data livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 180 timeoutSeconds: 5 readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 timeoutSeconds: 1 volumes: - name: data hostPath: path: /data1/docker/xinsrv/gitlab --- apiVersion: v1 kind: Service metadata: name: gitlab namespace: k8s-ops labels: name: gitlab spec: ports: - name: http port: 80 nodePort: 30088 - name: ssh port: 22 targetPort: ssh nodePort: 30022 type: NodePort selector: name: gitlab --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: gitlab namespace: k8s-ops annotations: kubernetes.io/ingress.class: traefik spec: rules: - host: gitlab.binghe.com http: paths: - backend: serviceName: gitlab servicePort: http
注意:在配置GitLab時,監聽主機時,不能使用IP地址,須要使用主機名或者域名,上述配置中,我使用的是gitlab.binghe.com主機名。
在命令行執行以下命令建立/data1/docker/xinsrv/gitlab目錄。
mkdir -p /data1/docker/xinsrv/gitlab
安裝GitLab,以下所示。
kubectl apply -f gitlab.yaml
查看k8s-ops命名空間部署狀況,以下所示。
[root@test10 k8s]# kubectl get pod -n k8s-ops NAME READY STATUS RESTARTS AGE gitlab-7b459db47c-5vk6t 0/1 Running 0 11s postgresql-79567459d7-x52vx 1/1 Running 0 30m redis-67f4cdc96c-h5ckz 1/1 Running 1 10h
也可使用以下命令查看。
[root@test10 k8s]# kubectl get pod --namespace=k8s-ops NAME READY STATUS RESTARTS AGE gitlab-7b459db47c-5vk6t 0/1 Running 0 36s postgresql-79567459d7-x52vx 1/1 Running 0 30m redis-67f4cdc96c-h5ckz 1/1 Running 1 10h
兩者效果同樣。
接下來,查看GitLab的端口映射,以下所示。
[root@test10 k8s]# kubectl get svc -n k8s-ops NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gitlab NodePort 10.96.153.100 <none> 80:30088/TCP,22:30022/TCP 2m42s postgresql ClusterIP 10.96.203.119 <none> 5432/TCP 32m redis ClusterIP 10.96.107.150 <none> 6379/TCP 10h
此時,能夠看到,能夠經過Master節點(test10)的主機名gitlab.binghe.com和端口30088就可以訪問GitLab。因爲我這裏使用的是虛擬機來搭建相關的環境,在本機訪問虛擬機映射的gitlab.binghe.com時,須要配置本機的hosts文件,在本機的hosts文件中加入以下配置項。
192.168.0.10 gitlab.binghe.com
注意:在Windows操做系統中,hosts文件所在的目錄以下。
C:\Windows\System32\drivers\etc
接下來,就能夠在瀏覽器中經過連接:http://gitlab.binghe.com:30088 來訪問GitLab了,以下所示。
此時,能夠經過用戶名root和密碼admin.1231來登陸GitLab了。
注意:這裏的用戶名是root而不是admin,由於root是GitLab默認的超級用戶。
到此,K8S安裝gitlab完成。
Habor是由VMWare公司開源的容器鏡像倉庫。事實上,Habor是在Docker Registry上進行了相應的企業級擴展,從而得到了更加普遍的應用,這些新的企業級特性包括:管理用戶界面,基於角色的訪問控制 ,AD/LDAP集成以及審計日誌等,足以知足基本企業需求。
注意:這裏將Harbor私有倉庫安裝在Master節點(test10服務器)上,實際生產環境中建議安裝在其餘服務器。
wget https://github.com/goharbor/harbor/releases/download/v1.10.2/harbor-offline-installer-v1.10.2.tgz
tar -zxvf harbor-offline-installer-v1.10.2.tgz
解壓成功後,會在服務器當前目錄生成一個harbor目錄。
注意:這裏,我將Harbor的端口修改爲了1180,若是不修改Harbor的端口,默認的端口是80。
(1)修改harbor.yml文件
cd harbor vim harbor.yml
修改的配置項以下所示。
hostname: 192.168.0.10 http: port: 1180 harbor_admin_password: binghe123 ###並把https註釋掉,否則在安裝的時候會報錯:ERROR:root:Error: The protocol is https but attribute ssl_cert is not set #https: #port: 443 #certificate: /your/certificate/path #private_key: /your/private/key/path
(2)修改daemon.json文件
修改/etc/docker/daemon.json文件,沒有的話就建立,在/etc/docker/daemon.json文件中添加以下內容。
[root@binghe~]# cat /etc/docker/daemon.json { "registry-mirrors": ["https://zz3sblpi.mirror.aliyuncs.com"], "insecure-registries":["192.168.0.10:1180"] }
也能夠在服務器上使用 ip addr 命令查看本機全部的IP地址段,將其配置到/etc/docker/daemon.json文件中。這裏,我配置後的文件內容以下所示。
{ "registry-mirrors": ["https://zz3sblpi.mirror.aliyuncs.com"], "insecure-registries":["192.168.175.0/16","172.17.0.0/16", "172.18.0.0/16", "172.16.29.0/16", "192.168.0.10:1180"] }
配置完成後,輸入以下命令便可安裝並啓動Harbor
[root@binghe harbor]# ./install.sh
安裝成功後,在瀏覽器地址欄輸入http://192.168.0.10:1180打開連接,輸入用戶名admin和密碼binghe123,登陸系統。
接下來,咱們選擇用戶管理,添加一個管理員帳戶,爲後續打包Docker鏡像和上傳Docker鏡像作準備。
密碼爲Binghe123。點擊確,此時,帳戶binghe還不是管理員,此時選中binghe帳戶,點擊「設置爲管理員」。
此時,binghe帳戶就被設置爲管理員了。到此,Harbor的安裝就完成了。
若是安裝Harbor後,你們須要修改Harbor的端口,能夠按照以下步驟修改Harbor的端口,這裏,我以將80端口修改成1180端口爲例
(1)修改harbor.yml文件
cd harbor vim harbor.yml
修改的配置項以下所示。
hostname: 192.168.0.10 http: port: 1180 harbor_admin_password: binghe123 ###並把https註釋掉,否則在安裝的時候會報錯:ERROR:root:Error: The protocol is https but attribute ssl_cert is not set #https: #port: 443 #certificate: /your/certificate/path #private_key: /your/private/key/path
(2)修改docker-compose.yml文件
vim docker-compose.yml
修改的配置項以下所示。
ports: - 1180:80
(3)修改config.yml文件
cd common/config/registry vim config.yml
修改的配置項以下所示。
realm: http://192.168.0.10:1180/service/token
(4)重啓Docker
systemctl daemon-reload systemctl restart docker.service
(5)重啓Harbor
[root@binghe harbor]# docker-compose down Stopping harbor-log ... done Removing nginx ... done Removing harbor-portal ... done Removing harbor-jobservice ... done Removing harbor-core ... done Removing redis ... done Removing registry ... done Removing registryctl ... done Removing harbor-db ... done Removing harbor-log ... done Removing network harbor_harbor [root@binghe harbor]# ./prepare prepare base dir is set to /mnt/harbor Clearing the configuration file: /config/log/logrotate.conf Clearing the configuration file: /config/nginx/nginx.conf Clearing the configuration file: /config/core/env Clearing the configuration file: /config/core/app.conf Clearing the configuration file: /config/registry/root.crt Clearing the configuration file: /config/registry/config.yml Clearing the configuration file: /config/registryctl/env Clearing the configuration file: /config/registryctl/config.yml Clearing the configuration file: /config/db/env Clearing the configuration file: /config/jobservice/env Clearing the configuration file: /config/jobservice/config.yml Generated configuration file: /config/log/logrotate.conf Generated configuration file: /config/nginx/nginx.conf Generated configuration file: /config/core/env Generated configuration file: /config/core/app.conf Generated configuration file: /config/registry/config.yml Generated configuration file: /config/registryctl/env Generated configuration file: /config/db/env Generated configuration file: /config/jobservice/env Generated configuration file: /config/jobservice/config.yml loaded secret from file: /secret/keys/secretkey Generated configuration file: /compose_location/docker-compose.yml Clean up the input dir [root@binghe harbor]# docker-compose up -d Creating network "harbor_harbor" with the default driver Creating harbor-log ... done Creating harbor-db ... done Creating redis ... done Creating registry ... done Creating registryctl ... done Creating harbor-core ... done Creating harbor-jobservice ... done Creating harbor-portal ... done Creating nginx ... done [root@binghe harbor]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
Jenkins是一個開源的、提供友好操做界面的持續集成(CI)工具,起源於Hudson(Hudson是商用的),主要用於持續、自動的構建/測試軟件項目、監控外部任務的運行(這個比較抽象,暫且寫上,不作解釋)。Jenkins用Java語言編寫,可在Tomcat等流行的servlet容器中運行,也可獨立運行。一般與版本管理工具(SCM)、構建工具結合使用。經常使用的版本控制工具備SVN、GIT,構建工具備Maven、Ant、Gradle。
使用 nfs 最大的問題就是寫權限,可使用 kubernetes 的 securityContext/runAsUser 指定 jenkins 容器中運行 jenkins 的用戶 uid,以此來指定 nfs 目錄的權限,讓 jenkins 容器可寫;也能夠不限制,讓全部用戶均可以寫。這裏爲了簡單,就讓全部用戶可寫了。
若是以前已經安裝過nfs,則這一步能夠省略。找一臺主機,安裝 nfs,這裏,我以在Master節點(test10服務器)上安裝nfs爲例。
在命令行輸入以下命令安裝並啓動nfs。
yum install nfs-utils -y systemctl start nfs-server systemctl enable nfs-server
在Master節點(test10服務器)上建立 /opt/nfs/jenkins-data
目錄做爲nfs的共享目錄,以下所示。
mkdir -p /opt/nfs/jenkins-data
接下來,編輯/etc/exports文件,以下所示。
vim /etc/exports
在/etc/exports文件文件中添加以下一行配置。
/opt/nfs/jenkins-data 192.168.175.0/24(rw,all_squash)
這裏的 ip 使用 kubernetes node 節點的 ip 範圍,後面的 all_squash
選項會將全部訪問的用戶都映射成 nfsnobody 用戶,無論你是什麼用戶訪問,最終都會壓縮成 nfsnobody,因此只要將 /opt/nfs/jenkins-data
的屬主改成 nfsnobody,那麼不管什麼用戶來訪問都具備寫權限。
這個選項在不少機器上因爲用戶 uid 不規範致使啓動進程的用戶不一樣,可是同時要對一個共享目錄具備寫權限時頗有效。
接下來,爲 /opt/nfs/jenkins-data
目錄受權,並從新加載nfs,以下所示。
#爲/opt/nfs/jenkins-data/目錄受權 chown -R 1000 /opt/nfs/jenkins-data/ #從新加載nfs-server systemctl reload nfs-server
在K8S集羣中任意一個節點上使用以下命令進行驗證:
#查看nfs系統的目錄權限 showmount -e NFS_IP
若是可以看到 /opt/nfs/jenkins-data 就表示 ok 了。
具體以下所示。
[root@test10 ~]# showmount -e 192.168.0.10 Export list for 192.168.0.10: /opt/nfs/jenkins-data 192.168.175.0/24 [root@test11 ~]# showmount -e 192.168.0.10 Export list for 192.168.0.10: /opt/nfs/jenkins-data 192.168.175.0/24
Jenkins 其實只要加載對應的目錄就能夠讀取以前的數據,可是因爲 deployment 沒法定義存儲卷,所以咱們只能使用 StatefulSet。
首先建立 pv,pv 是給 StatefulSet 使用的,每次 StatefulSet 啓動都會經過 volumeClaimTemplates 這個模板去建立 pvc,所以必須得有 pv,才能供 pvc 綁定。
建立jenkins-pv.yaml文件,文件內容以下所示。
apiVersion: v1 kind: PersistentVolume metadata: name: jenkins spec: nfs: path: /opt/nfs/jenkins-data server: 192.168.0.10 accessModes: ["ReadWriteOnce"] capacity: storage: 1Ti
我這裏給了 1T存儲空間,能夠根據實際配置。
執行以下命令建立pv。
kubectl apply -f jenkins-pv.yaml
建立service account,由於 jenkins 後面須要可以動態建立 slave,所以它必須具有一些權限。
建立jenkins-service-account.yaml文件,文件內容以下所示。
apiVersion: v1 kind: ServiceAccount metadata: name: jenkins --- kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 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/v1beta1 kind: RoleBinding metadata: name: jenkins roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: jenkins subjects: - kind: ServiceAccount name: jenkins
上述配置中,建立了一個 RoleBinding 和一個 ServiceAccount,而且將 RoleBinding 的權限綁定到這個用戶上。因此,jenkins 容器必須使用這個 ServiceAccount 運行才行,否則 RoleBinding 的權限它將不具有。
RoleBinding 的權限很容易就看懂了,由於 jenkins 須要建立和刪除 slave,因此才須要上面這些權限。至於 secrets 權限,則是 https 證書。
執行以下命令建立serviceAccount。
kubectl apply -f jenkins-service-account.yaml
建立jenkins-statefulset.yaml文件,文件內容以下所示。
apiVersion: apps/v1 kind: StatefulSet metadata: name: jenkins labels: name: jenkins spec: selector: matchLabels: name: jenkins serviceName: jenkins replicas: 1 updateStrategy: type: RollingUpdate template: metadata: name: jenkins labels: name: jenkins spec: terminationGracePeriodSeconds: 10 serviceAccountName: jenkins containers: - name: jenkins image: docker.io/jenkins/jenkins:lts imagePullPolicy: IfNotPresent ports: - containerPort: 8080 - containerPort: 32100 resources: limits: cpu: 4 memory: 4Gi requests: cpu: 4 memory: 4Gi env: - name: LIMITS_MEMORY valueFrom: resourceFieldRef: resource: limits.memory divisor: 1Mi - name: JAVA_OPTS # value: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 value: -Xmx$(LIMITS_MEMORY)m -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 volumeMounts: - name: jenkins-home mountPath: /var/jenkins_home livenessProbe: httpGet: path: /login port: 8080 initialDelaySeconds: 60 timeoutSeconds: 5 failureThreshold: 12 # ~2 minutes readinessProbe: httpGet: path: /login port: 8080 initialDelaySeconds: 60 timeoutSeconds: 5 failureThreshold: 12 # ~2 minutes # pvc 模板,對應以前的 pv volumeClaimTemplates: - metadata: name: jenkins-home spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 1Ti
jenkins 部署時須要注意它的副本數,你的副本數有多少就要有多少個 pv,一樣,存儲會有多倍消耗。這裏我只使用了一個副本,所以前面也只建立了一個 pv。
使用以下命令安裝Jenkins。
kubectl apply -f jenkins-statefulset.yaml
建立jenkins-service.yaml文件,主要用於後臺運行Jenkins,文件內容以下所示。
apiVersion: v1 kind: Service metadata: name: jenkins spec: # type: LoadBalancer selector: name: jenkins # ensure the client ip is propagated to avoid the invalid crumb issue when using LoadBalancer (k8s >=1.7) #externalTrafficPolicy: Local ports: - name: http port: 80 nodePort: 31888 targetPort: 8080 protocol: TCP - name: jenkins-agent port: 32100 nodePort: 32100 targetPort: 32100 protocol: TCP type: NodePort
使用以下命令安裝Service。
kubectl apply -f jenkins-service.yaml
jenkins 的 web 界面須要從集羣外訪問,這裏咱們選擇的是使用 ingress。建立jenkins-ingress.yaml文件,文件內容以下所示。
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: jenkins spec: rules: - http: paths: - path: / backend: serviceName: jenkins servicePort: 31888 host: jekins.binghe.com
這裏,須要注意的是host必須配置爲域名或者主機名,不然會報錯,以下所示。
The Ingress "jenkins" is invalid: spec.rules[0].host: Invalid value: "192.168.0.10": must be a DNS name, not an IP address
使用以下命令安裝ingress。
kubectl apply -f jenkins-ingress.yaml
最後,因爲我這裏使用的是虛擬機來搭建相關的環境,在本機訪問虛擬機映射的jekins.binghe.com時,須要配置本機的hosts文件,在本機的hosts文件中加入以下配置項。
192.168.0.10 jekins.binghe.com
注意:在Windows操做系統中,hosts文件所在的目錄以下。
C:\Windows\System32\drivers\etc
接下來,就能夠在瀏覽器中經過連接:http://jekins.binghe.com:31888 來訪問Jekins了。
Apache Subversion 一般被縮寫成 SVN,是一個開放源代碼的版本控制系統,Subversion 在 2000 年由 CollabNet Inc 開發,如今發展成爲 Apache 軟件基金會的一個項目,一樣是一個豐富的開發者和用戶社區的一部分。
SVN相對於的RCS、CVS,採用了分支管理系統,它的設計目標就是取代CVS。互聯網上免費的版本控制服務多基於Subversion。
這裏,以在Master節點(binghe101服務器)上安裝SVN爲例。
在命令行執行以下命令安裝SVN。
yum -y install subversion
依次執行以下命令。
#建立/data/svn mkdir -p /data/svn #初始化svn svnserve -d -r /data/svn #建立代碼倉庫 svnadmin create /data/svn/test
mkdir /data/svn/conf cp /data/svn/test/conf/* /data/svn/conf/ cd /data/svn/conf/ [root@binghe101 conf]# ll 總用量 20 -rw-r--r-- 1 root root 1080 5月 12 02:17 authz -rw-r--r-- 1 root root 885 5月 12 02:17 hooks-env.tmpl -rw-r--r-- 1 root root 309 5月 12 02:17 passwd -rw-r--r-- 1 root root 4375 5月 12 02:17 svnserve.conf
vim authz
配置後的內容以下所示。
[aliases] # joe = /C=XZ/ST=Dessert/L=Snake City/O=Snake Oil, Ltd./OU=Research Institute/CN=Joe Average [groups] # harry_and_sally = harry,sally # harry_sally_and_joe = harry,sally,&joe SuperAdmin = admin binghe = admin,binghe # [/foo/bar] # harry = rw # &joe = r # * = # [repository:/baz/fuz] # @harry_and_sally = rw # * = r [test:/] @SuperAdmin=rw @binghe=rw
vim passwd
配置後的內容以下所示。
[users] # harry = harryssecret # sally = sallyssecret admin = admin123 binghe = binghe123
vim svnserve.conf
配置後的文件以下所示。
### This file controls the configuration of the svnserve daemon, if you ### use it to allow access to this repository. (If you only allow ### access through http: and/or file: URLs, then this file is ### irrelevant.) ### Visit http://subversion.apache.org/ for more information. [general] ### The anon-access and auth-access options control access to the ### repository for unauthenticated (a.k.a. anonymous) users and ### authenticated users, respectively. ### Valid values are "write", "read", and "none". ### Setting the value to "none" prohibits both reading and writing; ### "read" allows read-only access, and "write" allows complete ### read/write access to the repository. ### The sample settings below are the defaults and specify that anonymous ### users have read-only access to the repository, while authenticated ### users have read and write access to the repository. anon-access = none auth-access = write ### The password-db option controls the location of the password ### database file. Unless you specify a path starting with a /, ### the file's location is relative to the directory containing ### this configuration file. ### If SASL is enabled (see below), this file will NOT be used. ### Uncomment the line below to use the default password file. password-db = /data/svn/conf/passwd ### The authz-db option controls the location of the authorization ### rules for path-based access control. Unless you specify a path ### starting with a /, the file's location is relative to the ### directory containing this file. The specified path may be a ### repository relative URL (^/) or an absolute file:// URL to a text ### file in a Subversion repository. If you don't specify an authz-db, ### no path-based access control is done. ### Uncomment the line below to use the default authorization file. authz-db = /data/svn/conf/authz ### The groups-db option controls the location of the file with the ### group definitions and allows maintaining groups separately from the ### authorization rules. The groups-db file is of the same format as the ### authz-db file and should contain a single [groups] section with the ### group definitions. If the option is enabled, the authz-db file cannot ### contain a [groups] section. Unless you specify a path starting with ### a /, the file's location is relative to the directory containing this ### file. The specified path may be a repository relative URL (^/) or an ### absolute file:// URL to a text file in a Subversion repository. ### This option is not being used by default. # groups-db = groups ### This option specifies the authentication realm of the repository. ### If two repositories have the same authentication realm, they should ### have the same password database, and vice versa. The default realm ### is repository's uuid. realm = svn ### The force-username-case option causes svnserve to case-normalize ### usernames before comparing them against the authorization rules in the ### authz-db file configured above. Valid values are "upper" (to upper- ### case the usernames), "lower" (to lowercase the usernames), and ### "none" (to compare usernames as-is without case conversion, which ### is the default behavior). # force-username-case = none ### The hooks-env options specifies a path to the hook script environment ### configuration file. This option overrides the per-repository default ### and can be used to configure the hook script environment for multiple ### repositories in a single file, if an absolute path is specified. ### Unless you specify an absolute path, the file's location is relative ### to the directory containing this file. # hooks-env = hooks-env [sasl] ### This option specifies whether you want to use the Cyrus SASL ### library for authentication. Default is false. ### Enabling this option requires svnserve to have been built with Cyrus ### SASL support; to check, run 'svnserve --version' and look for a line ### reading 'Cyrus SASL authentication is available.' # use-sasl = true ### These options specify the desired strength of the security layer ### that you want SASL to provide. 0 means no encryption, 1 means ### integrity-checking only, values larger than 1 are correlated ### to the effective key length for encryption (e.g. 128 means 128-bit ### encryption). The values below are the defaults. # min-encryption = 0 # max-encryption = 256
接下來,將/data/svn/conf目錄下的svnserve.conf文件複製到/data/svn/test/conf/目錄下。以下所示。
[root@binghe101 conf]# cp /data/svn/conf/svnserve.conf /data/svn/test/conf/ cp:是否覆蓋'/data/svn/test/conf/svnserve.conf'? y
(1)建立svnserve.service服務
建立svnserve.service文件
vim /usr/lib/systemd/system/svnserve.service
文件的內容以下所示。
[Unit] Description=Subversion protocol daemon After=syslog.target network.target Documentation=man:svnserve(8) [Service] Type=forking EnvironmentFile=/etc/sysconfig/svnserve #ExecStart=/usr/bin/svnserve --daemon --pid-file=/run/svnserve/svnserve.pid $OPTIONS ExecStart=/usr/bin/svnserve --daemon $OPTIONS PrivateTmp=yes [Install] WantedBy=multi-user.target
接下來執行以下命令使配置生效。
systemctl daemon-reload
命令執行成功後,修改 /etc/sysconfig/svnserve 文件。
vim /etc/sysconfig/svnserve
修改後的文件內容以下所示。
# OPTIONS is used to pass command-line arguments to svnserve. # # Specify the repository location in -r parameter: OPTIONS="-r /data/svn"
(2)啓動SVN
首先查看SVN狀態,以下所示。
[root@test10 conf]# systemctl status svnserve.service ● svnserve.service - Subversion protocol daemon Loaded: loaded (/usr/lib/systemd/system/svnserve.service; disabled; vendor preset: disabled) Active: inactive (dead) Docs: man:svnserve(8)
能夠看到,此時SVN並無啓動,接下來,須要啓動SVN。
systemctl start svnserve.service
設置SVN服務開機自啓動。
systemctl enable svnserve.service
接下來,就能夠下載安裝TortoiseSVN,輸入連接svn://192.168.0.10/test 並輸入用戶名binghe,密碼binghe123來鏈接SVN了。
拉取SVN鏡像
docker pull docker.io/elleflorio/svn-server
啓動SVN容器
docker run -v /usr/local/svn:/home/svn -v /usr/local/svn/passwd:/etc/subversion/passwd -v /usr/local/apache2:/run/apache2 --name svn_server -p 3380:80 -p 3690:3960 -e SVN_REPONAME=repos -d docker.io/elleflorio/svn-server
進入SVN容器內部
docker exec -it svn_server bash
進入容器後,能夠參照物理機安裝SVN的方式配置SVN倉庫。
注意:安裝Jenkins以前須要安裝JDK和Maven,我這裏一樣將Jenkins安裝在Master節點(binghe101服務器)。
運行如下命令如下載repo文件並導入GPG密鑰:
wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
執行以下命令安裝Jenkis。
yum install jenkins
接下來,修改Jenkins默認端口,以下所示。
vim /etc/sysconfig/jenkins
修改後的兩項配置以下所示。
JENKINS_JAVA_CMD="/usr/local/jdk1.8.0_212/bin/java" JENKINS_PORT="18080"
此時,已經將Jenkins的端口由8080修改成18080
在命令行輸入以下命令啓動Jenkins。
systemctl start jenkins
配置Jenkins開機自啓動。
systemctl enable jenkins
查看Jenkins的運行狀態。
[root@test10 ~]# systemctl status jenkins ● jenkins.service - LSB: Jenkins Automation Server Loaded: loaded (/etc/rc.d/init.d/jenkins; generated) Active: active (running) since Tue 2020-05-12 04:33:40 EDT; 28s ago Docs: man:systemd-sysv-generator(8) Tasks: 71 (limit: 26213) Memory: 550.8M
說明,Jenkins啓動成功。
首次安裝後,須要配置Jenkins的運行環境。首先,在瀏覽器地址欄訪問連接http://192.168.0.10:18080,打開Jenkins界面。
根據提示使用以下命令到服務器上找密碼值,以下所示。
[root@binghe101 ~]# cat /var/lib/jenkins/secrets/initialAdminPassword 71af861c2ab948a1b6efc9f7dde90776
將密碼71af861c2ab948a1b6efc9f7dde90776複製到文本框,點擊繼續。會跳轉到自定義Jenkins頁面,以下所示。
這裏,能夠直接選擇「安裝推薦的插件」。以後會跳轉到一個安裝插件的頁面,以下所示。
此步驟可能有下載失敗的狀況,可直接忽略。
須要安裝的插件
還有更多的插件可供選擇,可點擊 系統管理->管理插件進行管理和添加,安裝相應的Docker插件、SSH插件、Maven插件。其餘的插件能夠根據須要進行安裝。以下圖所示。
(1)配置JDK和Maven
在Global Tool Configuration中配置JDK和Maven,以下所示,打開Global Tool Configuration界面。
接下來就開始配置JDK和Maven了。
因爲我在服務器上將Maven安裝在/usr/local/maven-3.6.3目錄下,因此,須要在「Maven 配置」中進行配置,以下圖所示。
接下來,配置JDK,以下所示。
注意:不要勾選「Install automatically」
接下來,配置Maven,以下所示。
注意:不要勾選「Install automatically」
(2)配置SSH
進入Jenkins的Configure System界面配置SSH,以下所示。
找到 SSH remote hosts 進行配置。
配置完成後,點擊Check connection按鈕,會顯示 Successfull connection。以下所示。
至此,Jenkins的基本配置就完成了。
實現,SpringBoot項目中啓動類所在的模塊的pom.xml須要引入打包成Docker鏡像的配置,以下所示。
<properties> <docker.repostory>192.168.0.10:1180</docker.repostory> <docker.registry.name>test</docker.registry.name> <docker.image.tag>1.0.0</docker.image.tag> <docker.maven.plugin.version>1.4.10</docker.maven.plugin.version> </properties> <build> <finalName>test-starter</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- docker的maven插件,官網:https://github.com/spotify/docker‐maven‐plugin --> <!-- Dockerfile maven plugin --> <plugin> <groupId>com.spotify</groupId> <artifactId>dockerfile-maven-plugin</artifactId> <version>${docker.maven.plugin.version}</version> <executions> <execution> <id>default</id> <goals> <!--若是package時不想用docker打包,就註釋掉這個goal--> <goal>build</goal> <goal>push</goal> </goals> </execution> </executions> <configuration> <contextDirectory>${project.basedir}</contextDirectory> <!-- harbor 倉庫用戶名及密碼--> <useMavenSettingsForAuth>useMavenSettingsForAuth>true</useMavenSettingsForAuth> <repository>${docker.repostory}/${docker.registry.name}/${project.artifactId}</repository> <tag>${docker.image.tag}</tag> <buildArgs> <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE> </buildArgs> </configuration> </plugin> </plugins> <resources> <!-- 指定 src/main/resources下全部文件及文件夾爲資源文件 --> <resource> <directory>src/main/resources</directory> <targetPath>${project.build.directory}/classes</targetPath> <includes> <include>**/*</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
接下來,在SpringBoot啓動類所在模塊的根目錄建立Dockerfile,內容示例以下所示。
#添加依賴環境,前提是將Java8的Docker鏡像從官方鏡像倉庫pull下來,而後上傳到本身的Harbor私有倉庫中 FROM 192.168.0.10:1180/library/java:8 #指定鏡像製做做者 MAINTAINER binghe #運行目錄 VOLUME /tmp #將本地的文件拷貝到容器 ADD target/*jar app.jar #啓動容器後自動執行的命令 ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
根據實際狀況,自行修改。
注意:FROM 192.168.0.10:1180/library/java:8的前提是執行以下命令。
docker pull java:8 docker tag java:8 192.168.0.10:1180/library/java:8 docker login 192.168.0.10:1180 docker push 192.168.0.10:1180/library/java:8
在SpringBoot啓動類所在模塊的根目錄建立yaml文件,錄入叫作test.yaml文件,內容以下所示。
apiVersion: apps/v1 kind: Deployment metadata: name: test-starter labels: app: test-starter spec: replicas: 1 selector: matchLabels: app: test-starter template: metadata: labels: app: test-starter spec: containers: - name: test-starter image: 192.168.0.10:1180/test/test-starter:1.0.0 ports: - containerPort: 8088 nodeSelector: clustertype: node12 --- apiVersion: v1 kind: Service metadata: name: test-starter labels: app: test-starter spec: ports: - name: http port: 8088 nodePort: 30001 type: NodePort selector: app: test-starter
將項目上傳到SVN代碼庫,例如地址爲svn://192.168.0.10/test
接下來,在Jenkins中配置自動發佈。步驟以下所示。
點擊新建Item。
在描述文本框中輸入描述信息,以下所示。
接下來,配置SVN信息。
注意:配置GitLab的步驟與SVN相同,再也不贅述。
定位到Jenkins的「構建模塊」,使用Execute Shell來構建發佈項目到K8S集羣。
執行的命令依次以下所示。
#刪除本地原有的鏡像,不會影響Harbor倉庫中的鏡像 docker rmi 192.168.0.10:1180/test/test-starter:1.0.0 #使用Maven編譯、構建Docker鏡像,執行完成後本地Docker容器中會從新構建鏡像文件 /usr/local/maven-3.6.3/bin/mvn -f ./pom.xml clean install -Dmaven.test.skip=true #登陸 Harbor倉庫 docker login 192.168.0.10:1180 -u binghe -p Binghe123 #上傳鏡像到Harbor倉庫 docker push 192.168.0.10:1180/test/test-starter:1.0.0 #中止並刪除K8S集羣中運行的 /usr/bin/kubectl delete -f test.yaml #將Docker鏡像從新發布到K8S集羣 /usr/bin/kubectl apply -f test.yaml