本篇文章从实践角度介绍如何结合我们常用的 GitLab 与 Jenkins,通过 K8s 来实现项目的自动化部署,以公司目前正在使用的生产架构图做为此次javascript讲解的重点,如图所示:
本文涉及到的工具和技术包括:
- GitLab:常用的源代码管理系统;
- Jenkins(Jenkin开源中国s Pipeline):常用的自动化构建、部署工具,Pipejava环境变量配置line 以流水线的方式将构建、部署的各个步骤组织起来;
- docker(dockerfile):java模拟器容器引擎,所有应用最终都要以 docker 容器运行,dockerfile 是 docker 镜像定义文件;
- Kubernetes:Google 开源的容器编排管javascript百炼成仙理系统。
环境背景:
- 已使用 GitLab 做源码管理,源码按不同的环境建立不同的分支,如:dev (开发分支)、test(测试分支)、pre(预发分支)、master(生产分支);
- 已搭建 Jenkins 服务;
- 已有 docker Registry 服务,用于 docker 镜像的存储(javaee可开源节流以基于docker Registry 或 Harbor 自建,或使用云服务,本文使用阿里云容器镜像服务);
- 已部署了K8s集群。
预期效果:
- 分环境部署应用,使开发环境、测试环境、预发环境及生产环境隔离开来,其中,开发、测试、预发环境部署在同一个 K8s 集群中,但使用不同的 na架构图怎么制作mespace ,生产环境部署在阿里云,使用 ACK 容器服务;
- 配置尽可能通docker常用命令用化,只需要通过修改少量配置文件java环境变量配置的少量配置属性,就能完成新项目的开源矿工自动化部署配置;
- 开发、测试及预发环境在 push 代码时可以设置自动触发构建与部署,具体根据实际情况配置,生产环境使用单独 A开源众包CK 集群及单独 Jenkins 系统进行部署;
- 整体交互流程图如下:
项目配置文件
首先gitlab拉取代码到本地我们要在项目的根路径下添加一些必要的配置文件。如图所示
包括:
- dockerfile 文件,用于构建 docker 镜像文件;
-
Dockergitlab拉取代码到本地_build.sh
文件,用于将 docker 镜像打 Tag 后推送到镜像仓库中; - 项目 Yaml 文件,此文件为部署项目到 K8s 集群的主文件架构图模板。
dockerfile
在gitlab使用教程项目根目录中添加一个 dockerfile 文件(文件名就是 dockerfile),定义如何构建 docker 镜像,以 Java 项目为例:
# 镜像来源
FROM xxxxxxxxxxxxxxxxxxxxxxxxxx.cr.aliyuncs.com/billion_basic/alpine-java:latest
# 拷贝当前目录的应用到镜像
COPY target/JAR_NAME /application/
# 声明工作目录,不然找不到依赖包,如果有的话
WORKDIR /application
# 声明动态容器卷
VOLUME /application/logs
# 启动命令
# 设置时区
ENTRYPOINT ["java","-Duser.timezone=Asia/Shanghai","-Djava.security.egd=file:/dev/./urandom"]
CMD ["-jar","-Dspring.profiles.active=SPRING_ENV","-Xms512m","-Xmx1024m","/application/JAR_NAME"]
docker_build.sh
在项目根目录下创建一个 deploy
文件夹,此文件夹中存放各个环境项目的配置文件,其中Docker_build.sh
文件就是专为触发项目打包为镜像文件、重新打 Tag 后推送到镜像仓库中存在的,同样以 Java 项目为例:
# !/bin/bash
# 模块名称
PROJECT_NAME=$1
# 名称空间目录
WORKSPACE="/home/jenkins/workspace"
# 模块目录
PROJECT_PATH=$WORKSPACE/pro_$PROJECT_NAME
# jar 包目录
JAR_PATH=$PROJECT_PATH/target
# jar 包名称
JAR_NAME=$PROJECT_NAME.jar
# dockerfile 目录
dockerFILE_PATH="/$PROJECT_PATH/dockerfile"
# sed -i "s/VAR_CONTAINER_PORT1/$PROJECT_PORT/g" $PROJECT_PATH/dockerfile
sed -i "s/JAR_NAME/$JAR_NAME/g" $PROJECT_PATH/dockerfile
sed -i "s/SPRING_ENV/k8s/g" $PROJECT_PATH/dockerfile
cd $PROJECT_PATH
# 登录阿里云仓库
docker login xxxxxxxxxxxxxxxxxxxxxxxxxx.cr.aliyuncs.com -u 百瓶网 -p xxxxxxxxxxxxxxxxxxxxxxxxxx
# 构建模块镜像
docker build -t $PROJECT_NAME .
docker tag $PROJECT_NAME xxxxxxxxxxxxxxxxxxxxxxxxxx.cr.aliyuncs.com/billion_pro/pro_$PROJECT_NAME:$BUILD_NUMBER
# 推送到阿里云仓库
docker push xxxxxxxxxxxxxxxxxxxxxxxxxx.cr.aliyuncs.com/billion_pro/pro_$PROJECT_NAME:$BUILD_NUMBER
project.yaml
文件
project.yaml
定义了项目部署到K8sdocker安装部署集群中所需的项目名称、PV、PVC、namespace、副本数、镜像地址、服务端口、醒目自检、项目资源请开源节流求配置、文件挂载及 service 等:
# ------------------- PersistentVolume(定义PV) ------------------- #
apiVersion: v1
kind: PersistentVolume
metadata:
# 项目名称
name: pv-billionbottle-wx
namespace: billion-pro
labels:
alicloud-pvname: pv-billionbottle-wx
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
csi:
driver: nasplugin.csi.alibabacloud.com
volumeHandle: pv-billionbottle-wx
volumeAttributes:
server: "xxxxxxxxxxxxx.nas.aliyuncs.com"
path: "/k8s/java"
mountOptions:
- nolock,tcp,noresvport
- vers=3
---
# ------------------- PersistentVolumeClaim(定义PVC) ------------------- #
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-billionbottle-wx
namespace: billion-pro
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
selector:
matchLabels:
alicloud-pvname: pv-billionbottle-wx
---
# ------------------- Deployment ------------------- #
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: billionbottle-wx
name: billionbottle-wx
# 定义 namespace
namespace: billion-pro
spec:
# 定义副本数
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
k8s-app: billionbottle-wx
template:
metadata:
labels:
k8s-app: billionbottle-wx
spec:
serviceAccountName: default
imagePullSecrets:
- name: registrykey-k8s
containers:
- name: billionbottle-wx
# 定义镜像地址
image: $IMAGE_NAME
imagePullPolicy: IfNotPresent
# 定义自检
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 60
periodSeconds: 60
successThreshold: 1
tcpSocket:
port: 8020
timeoutSeconds: 1
ports:
# 定义服务端口
- containerPort: 8020
protocol: TCP
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 60
periodSeconds: 60
successThreshold: 1
tcpSocket:
port: 8020
timeoutSeconds: 1
# 定义项目资源配置
resources:
requests:
memory: "1024Mi"
cpu: "300m"
limits:
memory: "1024Mi"
cpu: "300m"
# 定义文件挂载
volumeMounts:
- name: pv-billionbottle-key
mountPath: "/home/billionbottle/key"
- name: pvc-billionbottle-wx
mountPath: "/billionbottle/logs"
volumes:
- name: pv-billionbottle-key
persistentVolumeClaim:
claimName: pvc-billionbottle-key
- name: pvc-billionbottle-wx
persistentVolumeClaim:
claimName: pvc-billionbottle-wx
---
# ------------------- Dashboard Service(定义service) ------------------- #
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: billionbottle-wx
name: billionbottle-wx
namespace: billion-pro
spec:
ports:
- port: 8020
targetPort: 8020
type: ClusterIP
selector:
k8s-app: billionbottle-wx
这里默认通过 Pipeline 定义了镜像的路径,可直接用变量去替换 $IMAGE_NAME
,且可以在这里直接指定容器的端口而不用去改开源是什么意思 dockerfile 文件模版(让模gitlab注册版文件gitlab怎么读在各个环境复用,通常不需要去做修改)docker是干什么的,同时添加了 ENV 的配置,可以直接读取 configmap 的配置文件。将 Service type 从默认的 NodePort
改为 ClusterIp
保证项目之间只在内部通讯。部署不同项目时只需要修改 docker_build.sh
和 Project.yaml
中的环境变量、项目名称及其他少量配置项,根目开源节流录下的 dockerfile 文件可以复用到各个环境。
部署时,我们要在 K8s 集群中的 Docker 镜像仓库拉取镜像,因此我们要先在 K8s 中创建镜像仓库访问凭证(imagePullSecr架构图怎么制作ets)。
# 登录 docker Registry 生成 /root/.docker/config.json 文件
docker login --username=your-username registry.cn-xxxxx.aliyuncs.com
# 创建 namespace billion-pro (我这里时根据项目的环境分支名称创建的namespace)
kubectl create namespace billion-pro
# 在 namespace billion-pro 中创建一个 secret
kubectl create secret registrykey-k8s aliyun-registry-secret --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson --name=billion-pro
```sh
### **Jenkinsfile (Pipeline)**
Jenkinsfile 是 Jenkins Pipeline 配置文件,遵循 Groovy 脚本规范。对于 Java 项目的构建部署,Jenkinsfile 的 Pipeline 脚本文件如下:
```pipeline
#!/bin/sh -ilex
def env = "pro"
def registry = "xxxxxxxxxxxxxxx.cn-shenzhen.cr.aliyuncs.com"
def git_address = "http://xxxxxxxxx/billionbottle/billionbottle-wx.git"
def git_auth = "1eb0be9b-ffbd-457c-bcbf-4183d9d9fc35"
def project_name = "billionbottle-wx"
def k8sauth = "8dd4e736-c8a4-45cf-bec0-b30631d36783"
def image_name = "${registry}/billion_pro/pro_${project_name}:${BUILD_NUMBER}"
pipeline{
environment{
BRANCH = sh(returnStdout: true,script: 'echo $branch').trim()
}
agent{
node{
label 'master'
}
}
stages{
stage('Git'){
steps{
git branch: '${Branch}', credentialsId: "${git_auth}", url: "${git_address}"
}
}
stage('maven build'){
steps{
sh "mvn clean package -U -DskipTests"
}
}
stage('docker build'){
steps{
sh "chmod 755 ./deploy/${env}_docker_build.sh && ./deploy/${env}_docker_build.sh ${project_name} ${env}"
}
}
stage('K8s deploy'){
steps{
sh "pwd && sed -i 's#\$IMAGE_NAME#${image_name}#' deploy/${env}_${project_name}.yaml"
kubernetesDeploy configs: "deploy/${env}_${project_name}.yaml", kubeconfigId: "${k8sauth}"
}
}
}
}
Jenkdocker容器insfile 的 Pipeline 脚本定义了整个自动化构建部署流程:
- Code Analyze:可以使用docker常用命令 SonarQube 之类的静态代码分析工具完成代码检查,这里先忽略;
- Mave开源节流n Build:启动一个 maven 的程序来完成项目 maven 的构建打包,也可以启动一个 mgitlab是干什么用的aven 容器,挂载 maven 本地仓库目录到宿主机,避免每次都需要重新下载依赖包;
- docker Build:构建 docker 镜像,并推送到镜像仓库,不同环境的镜像通过 tag 前缀区分,比如开发环境是
dev_
,测试环境是test_
,预发环境是prdocker是干什么的e_
,生产环境是pro_
; - K8s Deploy:使用 Jenkins 自带插件完成项目的部署,或已有项目的更新迭代,不同环境使用不同的参数配置,K8s 集群的访问凭证可用java模拟器 kube_config 来直接配置。
Jenkins 的配置Java
Jenk开源众包ins 任务配置
在 Jenkins 中创建一个 Pipeline 的任务,如图:
配置构建触发器,将架构图怎么制作目标分支设置为 master 分支,如图:docker容器
配置流水线,选择「Pipeline script」并配置 Pipeline 脚本文件,配置项开源矿工目 Git 地址,拉取源码凭证等,如图:
上图中引用的密钥凭据需要提前在 jenkins 中配置,如下图:
保存即完成了项目生产环境的 Jenkins 配置,其它环境同理,需要注意的是区分各个环境所对应的分支
Kubernetes 集群功能介绍
K8sjava怎么读 它是基于容器的集群编排引擎开源众包,具备扩张集群、滚动升级回滚、gitlab高可用方案弹性伸缩、自动治愈、服务发现等多种特性能力,结合目前生产环境的实际情况,重点介绍几个常用的功能点,如需详细了解其它功能,请直接在 Kubernets 官网 查询。
Kubernetes 架构图
从宏观上来说 Kubernetes 的整体架构,包含 Master、Node 以及 Etcd。
Master 即主节点,负责控制整个 kubernetes 集群。它包含 Api S开源矿工ergitlab官网ver、java模拟器Scheduler、Controller 等部分,它们都需要和 Etcd 进行交互以存储数据。
- Api Server:主要提供资源操作的统一架构师工资入口,这样就屏蔽了与 Etcd 的直接交互,功能包含安全、注册与发现等;
- Schedgitlab和github区别uller:负责按照一定的调度规则将 pod 调度到 Node 上;
- Controller:资源控制中心,确保资源处于预期的状态。
Node 即工作节点,为整个集java环境变量配置群提供计算力,是容器真正运行的地方,包括运行容器、kubelet、kube-proxy。
- kubelet:主要工作是管理容器的生命周期,结合 cAdvisor 进行监控gitlab高可用方案、健康检gitlab注册查以及定期上报节点状态;
- kube-proxy:主要开源是什么意思利用 service 提供集群内部的服务发现和负载均衡,同时监听 service/endpoints 变化刷新负载均衡。
容器编排
Kubernet开源阅读app下载安装es 中有诸多编排相关的控制资源,例如编排无状态应用的 deployment,编排有状态应用的 statefulset,编排守护进程 daemonset 以及编排离线任务的 job/cronjob 等等。开源矿工
我们以目前生产环境应用的 deployment 为例docker镜像, deployment 、replicatset 、pod 之间的关系是一种层层控制的关系,简单来开源节流什么意思说,replicatset 控制 pod 的数量,而 deployment 控制 replicatset 的版本属性,这种设计模式也为两种最基本的编排动作实现了基础,即数量控制的水平扩缩容,版本属性控制的更新/回滚。
水平扩缩容
水平扩缩容非常好理解,我们只需要修改 replicatset 控制的 pod 副本数量即可,比如从 2 改到 3 ,那么就完成了水平扩容这个动作,反之即水平收缩。
滚动更新部署(Rolling Update)
滚动部署是 K8s 中的默认部署策略gitlab官网,它用新版本的 pod 一个一个地替换应用程序先前版本的 pod ,而没有任何集群停机的时间,滚动部署缓慢地用新版本应java培训用程序的实例替换之前版本的应用程序实例开源代码网站github,如图所示:
在滚动更新的实际应用中我们可以配置 RollingUpdateStrategy 来控制滚gitlab注册动更新策略,另外还有两个选项可以让我们微调更新过程:
- maxS架构师urge :更新期间可以创建 pod 数量超过所需 pod 的数量,这可以是副本计数的绝对数量或百分比,默认值为25%;
- maxUnavailable :更新过程中不可用的 pod 数量,这可以是副本计数的绝对数量或百分比,默认值为25%。
微服务(service)
了解微服务前,我们要线了解一个很重要的资源对象 —— service
在微服务中, pod 可以对应实架构图怎么做word例,那么 service 对应的就是开源矿工微服务,而在服务调用的过程中,service 的出现解决了两个问题:
- pod 的 ip 不是固定的,利用非固定的 ip 进行网络调用不现实gitlab使用教程;
- 服务调用需要对不同的 pod 进行负载均衡。
servi开源软件ce 通过 label 选择器选取合适的 podocker安装部署d,构建出一个 endpoints,即 pod 负载均衡列表,实际运用中,一般我们会为同一个微服务gitlab怎么读的 pod 实例都搭上类似 app=xxx
的标签,架构图模板同时为该微服务创建一个标签选择器为 app=xxx
的 service。
Kubernetes 中的网络
K8s 的网络通讯,首先得有“三通”基础:
- node 到 pod 之间gitlab高可用方案可以互通;
- node 的 pod 之间可以互通;
- 不同gitlab官网 node 之间的 pod 可以互通。架构图模板
简单dockerfile来说不同 pod 之间通过 cni0/docker0 网桥实现了通讯,node 访问 pod 也是通过网桥通讯架构是什么意思, 而不同的 node 之间的 pod 通讯有很多种实现方式,包括现在比较普遍的 fla架构师和程序员的区别nnel 的 vxlan/hostgw 模式等,flannel 通过 etcd 获知其它 node 的网络信息,并会为本 nod开源中国e 创建路由表,最终使得不同 node 间可以实现跨主机通讯。
小结
到现在为止,已基本介绍清楚了我们生产环境整体架构中使用到的基础组件的相关概念,它们是如何运行的,开源以及微服务是怎么运开源众包行在 Kubernetes 中的,但涉及到配置中心、监控及告警等一些其它的组件docker常用命令暂未详细介绍,争取尽快更新这部分内容。