Docker,K8S,Jenkins容器自动化企业级项目实战大型项目架构


Docker,K8S,Jenkins容器自动化企业级项目实战大型项目架构

作为一个新入行的小白,参考了网上众多资料,也学到了很多知识,但搭建这样一套环境还是踩了不少坑。
当然,对于实际生成环境还有更多的坑要踩,目前这套环境仅在测试环境中跑通,还有很多细节需要完善,在此记录,仅当作自己学习的笔记。也欢迎爱好技术的同学共同交流,如有不对之处,欢迎大家指出。

Jenkins+GitLab+Docker+Kubernetes实现可持续自动化微服务。

Git的完全集成的软件开发平台(fully集成软件development platform)。与Github的区别在于可以免费且任意的创建私有仓库,并且可将服务部署在内网,通过管理人员配置的账号密码和访问权限来管理项目及代码,确保代码安全。

Spring boot

SpringBoot是一种全新的框架,目的是为了简化Spring应用的初始搭建以及开发过程。该框架使用特定的方式(集成starter,约定优于配置)来进行配置,从而使开发人员不需要再定义样板化的配置。SpringBoot提供了一种新的编程范式,可以更加快速便捷地开发Spring项目,在开发过程当中可以专注于应用程序本身的功能开发,而无需在Spring配置上花太大的工夫。

SpringBoot基于Sring4进行设计,继承了原有Spring框架的优秀基因。SpringBoot并不是一个框架,而是一些类库的集合。maven或者gradle项目导入相应依赖即可使用SpringBoot,而无需自行管理这些类库的版本。

https://github.com/docker/compose/releases

选择对应版本下载后移动至/usr/local/bin/文件夹下

mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
 
  • 1

添加执行权限

chmod a+x /usr/local/bin/docker-compose
 
  • 1

11.安装k8s基础环境

关闭 swap分区

swapoff -a
yes | cp /etc/fstab /etc/fstab_bak
cat /etc/fstab_bak |grep -v swap > /etc/fstab
 
  • 1
  • 2
  • 3

修改 /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
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

# 可能没有,追加

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
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

# 执行命令以应用

sysctl -p
 
  • 1

配置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=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

# ps: 由于官网未开放同步方式, 可能会有索引gpg检查失败的情况, 这时请用 yum install -y --nogpgcheck kubelet kubeadm kubectl 安装

# 卸载旧版本并安装新版K8S

yum remove -y kubelet kubeadm kubectl
yum install -y kubelet kubeadm kubectl
systemctl enable kubelet && systemctl start kubelet
 
  • 1
  • 2
  • 3

https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2

#k8s的文件路径请自己指定

mkdir /k8s        
rm -f /k8s/kubeadm-config.yaml    
cat <<EOF > /k8s/kubeadm-config.yaml  
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.20.4   #此处需替换为你安装的k8s版本号
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
# 根据服务器网速的情况,您需要等候 3 - 10 分钟
kubeadm init --config=/k8s/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"
cd /k8s
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
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
2. 执行如下命令,等待 3-10 分钟,直到所有的容器组处于 Running 状态
 
  • 1
 watch kubectl get pod -n kube-system -o wide
 
  • 1

查看 Master 节点初始化结果

kubectl get nodes -o wide
 
  • 1

status为READY说明初始化成功

3.初始化后输出中的

kubeadm join k8s.master:6443 --token k7r8hy.us6yyg6cx9qz9dw1 \
  --discovery-token-ca-cert-hash sha256:2980589c84da61dcac22f1e0d2dd11d2c4331e2ac0951f1ae2bcccb2c397360c \
  --control-plane --certificate-key 00df25ba37c22591d93fb3336cd11f7d7a1bbe58d7c068940b0dd10a88251e70
 
  • 1
  • 2
  • 3

# 可以用来将node节点加入,也可以后续再用命令生成,但需注意k8s.master要在node节点中的/etc/hosts中,且替换为你自己的设置

HTTP。

Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。

在master节点执行,在你的k8s目录中创建下面的文件,如本例中的/k8s,并注意yaml文件的缩进格式

1.创建ingress-nginx命名空间

? 创建ingress-nginx-namespace.yaml文件,文件内容如下所示。

 apiVersion: v1
      kind: Namespace
      metadata:
      name: ingress-nginx
      labels:
        name: ingress-nginx
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

? 执行如下命令创建ingress-nginx命名空间。

  kubectl apply -f ingress-nginx-namespace.yaml
 
  • 1

2.安装ingress controller

? 创建ingress-nginx-mandatory.yaml文件,文件内容如下所示。

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 "-"
      # Here: "-"
      # 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

---
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328

执行如下命令安装ingress controller。

kubectl apply -f ingress-nginx-mandatory.yaml
 
  • 1

3.安装K8S SVC:ingress-nginx

? 主要是用来用于暴露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
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

? 执行如下命令安装。

  kubectl apply -f service-nodeport.yaml
 
  • 1

4.访问K8S SVC:ingress-nginx

? 查看ingress-nginx命名空间的部署情况,如下所示。

kubectl get pod -n ingress-nginx
 
  • 1

? 在命令行服务器命令行输入如下命令查看ingress-nginx的端口映射情况。

kubectl get svc -n ingress-nginx
 
  • 1

? 所以,可以通过Master节点的IP地址和30080端口号来访问ingress-nginx,如下所示。

 curl 10.1.1.129:30080
 
  • 1

? default backend - 404

? 也可以在浏览器打开http://10.1.1.129:30080 来访问ingress-nginx

com主机名。

? 在命令行执行如下命令创建/data1/docker/xinsrv/gitlab目录。

mkdir -p /data1/docker/xinsrv/gitlab
 
  • 1

? 安装GitLab,如下所示。

kubectl apply -f gitlab.yaml
 
  • 1

5.安装完成

查看k8s-ops命名空间部署情况,如下所示。

[root@master]# kubectl get pod -n k8s-ops
NAME             READY  STATUS  RESTARTS  AGE
gitlab-7b459db47c-5vk6t    1/1   Running  0     11s
postgresql-79567459d7-x52vx  1/1   Running  0     30m
redis-67f4cdc96c-h5ckz    1/1   Running  1     10h
 
  • 1
  • 2
  • 3
  • 4
  • 5

接下来,查看GitLab的端口映射,如下所示。

[root@master]# 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
 
  • 1
  • 2
  • 3
  • 4
  • 5

此时,可以看到,可以通过Master节点的主机名和端口30088就能够访问GitLab。如果是虚拟机搭建的测试环境,则需要查看gitlab的pod运行在哪个节点,然后用node节点ip+端口访问。

本例中,登陆时用户名为root,密码为admin12345。注意:这里的用户名是root而不是admin,因为root是GitLab默认的超级用户。

到此,K8S安装gitlab完成。

链接。
输入你设置的用户名和密码
接下来,我们选择用户管理,添加一个管理员账户,为后续打包Docker镜像和上传Docker镜像做准备。
系统管理——用户管理——创建用户

在这里插入图片描述
? 输入对应信息后点确定
在这里插入图片描述
? 创建完成后,选中该用户,设置为管理员。
在这里插入图片描述
7.安装后如果要修改端口,如修改为1180
需要修改3个文件
(1)修改harbor.yml文件,在harbor文件夹中

hostname: 10.1.1.1
http:
  port: 1180
 
  • 1
  • 2
  • 3

? (2)修改docker-compose.yml文件,在harbor文件夹中

ports:
    - 1180:80
 
  • 1
  • 2

? (3)修改config.yml文件

cd common/config/registry
vim config.yml
 
  • 1
  • 2

? 修改的配置项如下所示。

realm: http://10.1.1.1:1180/service/token
 
  • 1

? (4)重启Docker

systemctl daemon-reload
systemctl restart docker.service
 
  • 1
  • 2

? (5)重启Harbor

docker-compose down
./prepare
docker-compose up -d
 
  • 1
  • 2
  • 3

boot项目到K8s集群

4.1 拉取java8镜像

在任意一台服务器上拉取java8镜像,然后推送至harbor仓库,一会打包构建docker镜像的时候会用到。

docker pull java:8
docker tag java:8 10.1.1.132:1180/library/java:8
docker login 10.1.1.1320:1180
docker push 10.1.1.132:1180/library/java:8
 
  • 1
  • 2
  • 3
  • 4

4.2 调整SpringBoot项目的配置

在SpringBoot项目中启动类所在的模块的pom.xml需要引入打包成Docker镜像的配置,在对应的语句块下添加下面的内容:

<properties>
    
    <docker.repostory>10.1.1.132:1180docker.repostory>
    
    <docker.registry.name>testdocker.registry.name>
    <docker.image.tag>1.0.0docker.image.tag>
    <docker.maven.plugin.version>1.4.10docker.maven.plugin.version>
properties>

<build>
    	
        <finalName>test-starterfinalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
            
            
            
            <plugin>
                <groupId>com.spotifygroupId>
                <artifactId>dockerfile-maven-pluginartifactId>
                <version>${docker.maven.plugin.version}version>
                <executions>
                    <execution>
                    <id>defaultid>
                    <goals>
                        
                        <goal>buildgoal>
                        <goal>pushgoal>
                    goals>
                    execution>
                executions>
                <configuration>
                    <contextDirectory>${project.basedir}contextDirectory>
                    
             <useMavenSettingsForAuth>useMavenSettingsForAuth>trueuseMavenSettingsForAuth>
             <repository>${docker.repostory}/${docker.registry.name}/${project.artifactId}repository>
                    <tag>${docker.image.tag}tag>
                    <buildArgs>
                        
                        <JAR_FILE>target/${project.build.finalName}.jarJAR_FILE>
                    buildArgs>
                configuration>
            plugin>

        plugins>
        
        <resources>
            
            <resource>
                <directory>src/main/resourcesdirectory>
                <targetPath>${project.build.directory}/classestargetPath>
                <includes>
                    <include>**/*include>
                includes>
                <filtering>truefiltering>
            resource>
        resources>
    build>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

接下来,在SpringBoot启动类所在模块的根目录创建Dockerfile,内容示例如下所示。

#添加依赖环境,前提是将Java8的Docker镜像从官方镜像仓库pull下来,然后上传到自己的Harbor私有仓库中
FROM 10.1.1.132:1180/library/java:8
#指定镜像制作作者,可自己随意设置
MAINTAINER abc   
#运行目录
VOLUME /tmp
#将本地的文件拷贝到容器,一般在项目的target目录下,要根据项目自己修改
ADD target/*jar app.jar
#启动容器后自动执行的命令
ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar" ]
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在SpringBoot启动类所在模块的根目录创建yaml文件,录入叫做test.yaml文件,其中test-starter替换为你启动pom中的build语句块下设置的名字,内容如下所示。

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: 10.1.1.132:1180/test/test-starter:1.0.0
        ports:
        - containerPort: 8088   #修改成你项目的端口

---
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
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

4.3 Jenkins配置发布项目

先上传代码到gitlab你的项目上,并按上面的步骤创建好yaml和dockerfile文件,然后创建一个自由风格的jenkins项目,并输入项目名称:
在这里插入图片描述

点击配置进入项目配置页面
在这里插入图片描述
简单介绍几个配置,具体深入的配置可以参考后面给出的参考文档。

丢弃旧的构建,可以节约磁盘空间,这里可以根据项目需求设置。
在这里插入图片描述

这里配置你的gitlab源码访问权限

在这里插入图片描述

这里根据需要配置构建触发的条件

在这里插入图片描述

构建里面选择新增构建,执行shell

在这里插入图片描述

在解析shell代码之前,需要给jenkins配置docker用户组的权限,否则构建时会报错,网上查到的结果无非有三种,

一是通过修改/var/run/docker.sock文件的权限,由660改成666

chmod 666 /var/run/docker.sock
 
  • 1

二是将jenkins加入docker用户组

usermod -a -G docker jenkins
 
  • 1

三是修改docker的启动文件配置,感兴趣的同学可以自己去尝试,这个方法我没有试过。

这里我用过前两种方法,但第二种似乎并不起作用,构建时仍然会报错。所以暂时用的第一种方式,但这种方式在生产中还是要慎用,毕竟存在一定的安全问题。

shell代码解析

#如果原来本地有同名镜像,则删除本地原有的镜像,不会影响Harbor仓库中的镜像,如果没有,可以在第一次构建时注释掉,否则会报错,仓库的项目名称要根据需要修改
docker rmi 10.1.1.132: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仓库,根据你创建的harbor用户来设置
docker login 10.1.1.132:1180 -u test -p 123456
#上传镜像到Harbor仓库
docker push 10.1.1.132:1180/test/test-starter:1.0.0
#先将项目目录下的yaml文件复制到k8s集群master节点的执行目录
scp test.yaml root@master:/k8s/demo/
#远程登陆到k8s集群的master节点,前提是前面在jenkins中配置了ssh登陆远程服务器,并测试连接成功,这里使用重定向完成远程服务器操作,EOF是重定向结束标志,大小写敏感
ssh -tt root@master << EOF
#如果非第一次运行,先停止并删除K8S集群中运行的pod;否则注释掉这一行,避免构建报错
/usr/bin/kubectl delete -f /k8s/demo/test.yaml
#将Docker镜像重新发布到K8S集群,注意文件的路径要写正确
/usr/bin/kubectl apply -f /k8s/demo/test.yaml
#执行完成后记得退出远程登陆
exit
#并结束重定向操作
EOF
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

配置完成后,保存退出项目配置。

在项目界面点击立即构建,执行构建。

在这里插入图片描述

? 点击构建可以进入查看日志

在这里插入图片描述

在这里插入图片描述

最后显示SUCCESS,则表示构建成功。如果失败,则可以根据日志调整。

构建完成后可以在你的master节点查看pod

kubectl get pod --all-namespaces
 
  • 1

在这里插入图片描述

以上状态表示pod成功运行。可以通过下面命令查看暴露的端口

kubectl get svc
 
  • 1

在这里插入图片描述

30001即是本次构建项目的访问端口,可以通过master节点ip+端口或域名+端口的形式访问

访问结果如下:

在这里插入图片描述

至此,一个spring boot的项目就构建完成并发布至k8s集群中了。当然,实际生产中的项目远比这个demo复杂,构建之前数据库的配置等操作也一样要先进行,否则构建过程可能会报错。

5.遗留问题

1).如何在k8s中安装jenkins并在pod中安装maven?

由于本案例中先采用的k8s安装jenkins,但是发现没有找到如何安装maven的方法,虽然可以强制登陆到pod中安装maven,但这似乎并不是解决问题的方式,后面我会再查询相关解决方式。

2).如何在k8s中安装jenkins并将项目构建部署在这个k8s中?

? 方式一:同样采用ssh远程执行命令的方式

? 方式二:通过jenkins中的k8s调度配置,有待研究

3).配置jenkins多节点,master-slave模式

大致看过相关配置文件,其实并不复杂,由于目前我暂时用不到,所以就没有在教程中实现。其实当时采用k8s安装jenkins想的就是k8s的弹性伸缩功能,但由于目前水平有限,暂时还没有研究,后续有待学习提高。

4).maven构建项目时的module顺序问题,有时顺序不正确可能会导致构建失败

之所以配图用的是spring boot官网的demo展示构建结果,是因为我在这次实验中的开源项目因构建顺序问题,无法成功构建。之前同样的项目同样的配置在我笔记本电脑的虚拟机上构建时的module顺序和这次不同,导致了这个问题的出现。虽然网上有说过maven在构建时,会自动根据module的依赖关系选择构建顺序,但因本人非开发,不是很懂,因此,暂时还没有找到问题症结。后面也会继续跟踪该问题,直到了解并解决。

5).k8s安装gitlab的持久化问题

gitlab在k8s中安装存在代码持久化保存的问题,虽然我们可以通过其它方式,定期备份代码,但是一旦pod出现问题,可能会导致代码丢失。虽然目前没有查询文档,但大概的解决思路有几种:

一是通过物理机安装gitlab

二是通过修改gitlab的yaml文件,在创建pod时将卷挂载到物理机磁盘上,如jenkins使用的nfs

三是通过自动备份的方式定期备份pod中的代码至物理机磁盘

由于时间原因,暂时不做展开。

6).webhook问题

在jenkins的构建触发条件中,有一项可以通过gitlab中代码的改动自动触发构建,这个在第一次实验中我使用过,如果配置邮件发送构建状态,则可以极大提高效率,这里暂时就不做展开,在下一个版本中会逐步完善。

6.总结

总体来说,这一整套环境的搭建其实并不复杂,网上也有很多类似教程,但由于本人初次接触,且经验欠缺,还是花了一定的时间,遇到的主要困难集中在以下几个方面:

1).对原理了解的欠缺

整套环境中,无论哪个软件拿出来,都可以单独出几本书,稍微简单一些的jenkins,虽然整体了解并不复杂,但它可以做二次开发。基于对项目的需求,有很强的定制性。并且,这里只是通过构建spring boot项目就遇到了这么多的问题,还没有构建其它语言的项目呢。因此,了解每个软件的原理很重要。

这里尤其要说的是k8s,我知道这个东西也才几个月,通过网上的一些资料,知道它并不是简简单单的容器编排管理工具。它更像是一种思想和趋势,要想深入学习没有项目实践是很困难的,尤其是能够用到k8s的项目一定不是小项目,这也进一步增加了学习的难度。不过万事开头难,虽然目前仅仅走出了一小步,but it’s better than never。

2).解决问题的思路

由于对原理的欠缺,就必然导致解决问题遇到的麻烦。虽然全部自己查找资料解决了,但大多数问题的解决时间堪忧。其实遇到问题基本上还是逃不开看现象、看日志等方面,经验也是这样慢慢积累的。

3).开发经验的重要性

虽然说作为一个运维工程师,你完全可以选择不懂代码,但这不是我的目标。除非你要去做运维开发,否则懂代码不是让你能写出多好的项目,而是你要懂得基本的原理和代码逻辑,能够独立的排除因代码导致安装、配置故障;其次学习编程重要的编程的思想,了解算法和数据结构背后计算机处理数据的逻辑。懂得了这些对于运维工程师的提升虽然不是立竿见影,但绝对会厚积薄发。

4).钻研精神和自我挖坑

技术之路充满艰难险阻,尤其是对于我这样半路出家的人。但既然选择了,就不要跟自己设定下限,而是要不断突破上限。我始终坚信没有解决不了的问题,只是花费的时间和代价问题,我们积累经验的过程也就是减少付出时间和代价的过程。其次在平时实验环境中要勇敢的给自己挖坑,尽量把遇到的问题做展开,如果这样如果那样,我该如何应对,这样才能够快速成长,我想技术之路不只是给智者的,也是给勤劳者的。

7 参考文档

感谢伟大的互联网,为我提供了几乎是一切!

排名不分先后:

安装部署篇

https://ken.io/note/centos7-gitlab-install-tutorial

https://www.jianshu.com/p/400b4516b98e

https://www.cnblogs.com/guolianyu/p/9477028.html

https://juejin.cn/post/6844903943051411469

https://juejin.cn/post/6844904142922743821

配置管理篇

https://www.cnblogs.com/shawhe/p/11313633.html

https://www.cnblogs.com/zhangs1986/p/11102786.html

https://blog.csdn.net/qq_36184009/article/details/71079726

https://www.jianshu.com/p/5f671aca2b5a

https://mingshan.fun/2018/08/18/build-springboot-by-jenkins-to-deploy-into-docker/

https://yuerblog.cc/2019/02/25/flannel-and-calico/

https://www.jianshu.com/p/86d288ea64c4

https://www.linuxidc.com/Linux/2020-05/163161.htm

https://blog.csdn.net/liubingyu12345/article/details/80737412

https://blog.csdn.net/linfen1520/article/details/109045063

https://juejin.cn/post/6844904154133954567#heading-0

https://blog.51cto.com/14143894/2482586

https://www.jianshu.com/p/7444149be6c6

https://www.cnblogs.com/hellxz/p/easyway_jenkins_integration_k8s.html