一、简介
DevOps (Development和Operations的组合词)是一系列做法和工具,可以使 IT 和软件开发团队之间的流程实现自动化。其中,随着敏捷软件开发日趋流行,持续集成 (CI) 和持续交付 (CD) 已经成为该领域一个理想的解决方案。在 CI/CD 工作流中,每次集成都通过自动化构建来验证,包括编码、发布和测试,从而帮助开发者提前发现集成错误,团队也可以快速、安全、可靠地将内部软件交付到生产环境。
我们借助
KubeSphere
来学习DevOps
:KubeSphere DevOps 系统步骤如下:
- 拉取代码
- 项目编译
- 构建镜像
- 推送镜像仓库
- 部署k8s
二、首先创建一个devops工程以及流水线
1、创建流水线工程
2、创建流水线
3、 编辑流水线
选择上面的流水线模板:
上面的模板我们需要自定义,主要分为如下几个步骤:
- 拉取代码
- 项目编译
- 构建镜像
- 推送镜像仓库
- 部署k8s
三、开始定义流水线之拉取代码
1、编写第一个拉取代码的步骤
点击添加步骤:
可以参考kubesphere的官网,可供选择的有4个容器:
点击添加嵌套步骤主要是用来拉取代码:
下面我们再加一个嵌套步骤,用来看拉取代码是否成功:
点击确认:
点击保存:
下面我们点击运行,看看第一步拉取代码是否成功:
点击进去:
发现失败了,可以查看日志:
重新编辑流水线,将容器换成maven:
点击运行,查看日志,第一步代码已经拉取成功:
四、开始定义流水线之项目编译
1、开始编写项目编译步骤
2、先指定容器为maven
3、添加嵌套命令ls,确定代码
4、再次添加嵌套的shell命令用来打包项目代码
mvn clean package -Dmaven.skip.test=true
5、点击确定保存,运行流水线
注意:
在使用mvn clean pacgage Dmaven.test.skip=true
命令进行编译打包时,Maven会从中央仓库去下载依赖,这样速度会很慢,我们需要修改Maven的配置文件ks-devops-agent,修改为阿里云的,注意这个要使用admin账户登录,选择集群管理
下面我们重新运行看看速度:
可以发现是从阿里云下载的依赖了
五、开始定义流水线之构建镜像
1、开始编写构建镜像命令,下面我们以ruoyi-auth服务为例,指定容器
2、添加嵌套步骤,查看编译好的代码结构
我们先运行看一下:
3、下面根据上面的目录编写生成镜像的命令
点击保存
4、下面我们点击运行测试一下
由上可知,编译镜像成功!
5、下面我们把后端其他的镜像也一起构建,我们使用并行的方式
点击添加并行阶段:
可以发现上面一个一个添加太慢了,我们直接编辑Jenkinsfile文件:
我们直接找到这部分进行修改,具体内容如下:
pipeline { agent { node { label 'maven' } } stages { stage('拉取代码') { agent none steps { container('maven') { git(url: 'https://gitee.com/kgf897570/ruoyi-cloud.git', branch: 'master', credentialsId: 'ruoyi-cloud-gitee', changelog: true, poll: false) sh 'ls' } } } stage('项目编译') { agent none steps { container('maven') { sh 'ls' sh 'mvn clean package -Dmaven.skip.test=true' sh 'ls' } } } stage('default-2') { parallel { stage('构建ruoyi-auth镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-auth ' sh 'docker build -t ruoyi-auth:latest -f ruoyi-auth/Dockerfile ./ruoyi-auth/' } } } stage('构建ruoyi-monitor镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-visual/ruoyi-monitor/' sh 'docker build -t ruoyi-monitor:latest -f ruoyi-visual/ruoyi-monitor/Dockerfile ./ruoyi-visual/ruoyi-monitor/' } } } stage('构建ruoyi-gateway镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-gateway/' sh 'docker build -t ruoyi-gateway:latest -f ruoyi-gateway/Dockerfile ./ruoyi-gateway/' } } } stage('构建ruoyi-file镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-modules/ruoyi-file/' sh 'docker build -t ruoyi-file:latest -f ruoyi-modules/ruoyi-file/Dockerfile ./ruoyi-modules/ruoyi-file/' } } } stage('构建ruoyi-job镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-modules/ruoyi-file/' sh 'docker build -t ruoyi-file:latest -f ruoyi-modules/ruoyi-file/Dockerfile ./ruoyi-modules/ruoyi-file/' } } } stage('构建ruoyi-system镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-modules/ruoyi-system/' sh 'docker build -t ruoyi-system:latest -f ruoyi-modules/ruoyi-system/Dockerfile ./ruoyi-modules/ruoyi-system/' } } } } } stage('推送镜像仓库') { when { branch 'master' } steps { container('maven') { sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest ' sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest ' } } } stage('部署到dev环境') { steps { input(id: 'deploy-to-dev', message: 'deploy to dev?') kubernetesDeploy(configs: 'deploy/dev-ol/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID") } } stage('deploy to production') { steps { input(id: 'deploy-to-production', message: 'deploy to production?') kubernetesDeploy(configs: 'deploy/prod-ol/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID") } } } environment { DOCKER_CREDENTIAL_ID = 'dockerhub-id' GITHUB_CREDENTIAL_ID = 'github-id' KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig' REGISTRY = 'docker.io' DOCKERHUB_NAMESPACE = 'docker_username' GITHUB_ACCOUNT = 'kubesphere' APP_NAME = 'devops-java-sample' } parameters { string(name: 'TAG_NAME', defaultValue: '', description: '') } }
最后结果如下:
下面我们直接点击运行试一下:
可以发现运行成功
六、开始定义流水线之推送到镜像仓库
1、直接编辑
Jenkinsfile
文件,在environment
定义环境变量,可以直接使用$
来引用。2、创建登录凭证:
3、修改推送镜像的Jenkinsfile文件部分
stage('推送镜像仓库') { agent none steps { container('maven') { withCredentials([usernamePassword(credentialsId : 'aliyu-ruoyi' ,passwordVariable : 'DOCKER-PWD-VAR' ,usernameVariable : 'DOCKER-USER-VAR' ,)]) { sh 'echo "$DOCKER_PWD_VAR" | docker login $REGISTRY -u "$DOCKER_USER_VAR" --password-stdin ' //表示登录到阿里云仓库 sh 'docker tag ruoyi-auth:latest $REGISTRY/$DOCKERHUB_NAMESPACE/ruoyi-auth:SNAPSHOT-$BUILD_NUMBER ' //打上标签 sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/ruoyi-auth:SNAPSHOT-$BUILD_NUMBER ' //推送到阿里云仓库 } } } }
4、下面我们将环境变量以及推送镜像部分的修改放到流水线的Jenkinsfile中
5、下面我们保存然后运行一下
由上可知登录阿里云仓库以及打版本号都已经成功
推送失败了,没有权限是我们的阿里云凭证搞错了,修改后重新推送:
成功,查看阿里云仓库:
6、上面完整的Jenkinsfile内容如下
pipeline { agent { node { label 'maven' } } stages { stage('拉取代码') { agent none steps { container('maven') { git(url: 'https://gitee.com/kgf897570/ruoyi-cloud.git', branch: 'master', credentialsId: 'ruoyi-cloud-gitee', changelog: true, poll: false) sh 'ls' } } } stage('项目编译') { agent none steps { container('maven') { sh 'ls' sh 'mvn clean package -Dmaven.skip.test=true' sh 'ls' } } } stage('default-2') { parallel { stage('构建ruoyi-auth镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-auth ' sh 'docker build -t ruoyi-auth:latest -f ruoyi-auth/Dockerfile ./ruoyi-auth/' } } } stage('构建ruoyi-monitor镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-visual/ruoyi-monitor/' sh 'docker build -t ruoyi-monitor:latest -f ruoyi-visual/ruoyi-monitor/Dockerfile ./ruoyi-visual/ruoyi-monitor/' } } } stage('构建ruoyi-gateway镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-gateway/' sh 'docker build -t ruoyi-gateway:latest -f ruoyi-gateway/Dockerfile ./ruoyi-gateway/' } } } stage('构建ruoyi-file镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-modules/ruoyi-file/' sh 'docker build -t ruoyi-file:latest -f ruoyi-modules/ruoyi-file/Dockerfile ./ruoyi-modules/ruoyi-file/' } } } stage('构建ruoyi-job镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-modules/ruoyi-file/' sh 'docker build -t ruoyi-file:latest -f ruoyi-modules/ruoyi-file/Dockerfile ./ruoyi-modules/ruoyi-file/' } } } stage('构建ruoyi-system镜像') { agent none steps { container('maven') { sh 'ls -l ruoyi-modules/ruoyi-system/' sh 'docker build -t ruoyi-system:latest -f ruoyi-modules/ruoyi-system/Dockerfile ./ruoyi-modules/ruoyi-system/' } } } } } stage('推送镜像仓库') { agent none steps { container('maven') { withCredentials([usernamePassword(credentialsId : 'aliyu-ruoyi' ,passwordVariable : 'DOCKER_PWD_VAR' ,usernameVariable : 'DOCKER_USER_VAR' ,)]) { sh 'echo "$DOCKER_PWD_VAR" | docker login $REGISTRY -u "$DOCKER_USER_VAR" --password-stdin ' sh 'docker tag ruoyi-auth:latest $REGISTRY/$DOCKERHUB_NAMESPACE/ruoyi-auth:SNAPSHOT-$BUILD_NUMBER ' sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/ruoyi-auth:SNAPSHOT-$BUILD_NUMBER ' } } } } stage('部署到dev环境') { steps { input(id: 'deploy-to-dev', message: 'deploy to dev?') kubernetesDeploy(configs: 'deploy/dev-ol/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID") } } stage('deploy to production') { steps { input(id: 'deploy-to-production', message: 'deploy to production?') kubernetesDeploy(configs: 'deploy/prod-ol/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID") } } } environment { DOCKER_CREDENTIAL_ID = 'dockerhub-id' GITHUB_CREDENTIAL_ID = 'github-id' KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig' REGISTRY = 'registry.cn-zhangjiakou.aliyuncs.com' DOCKERHUB_NAMESPACE = 'kgf-ruoyi' GITHUB_ACCOUNT = 'kubesphere' APP_NAME = 'devops-java-sample' } parameters { string(name: 'TAG_NAME', defaultValue: '', description: '') } }
7、创建并行推送镜像到阿里云仓库
先创建一个并行的模板:
然后将Jenkinsfile的内容拷贝出来进行手动修改:
开始将我们所有的后台服务都进行编写推送:
点击运行测试推送:
由上可知推送成功,我们去仓库查看:
下面开始部署项目
六、开始定义流水线之部署项目到k8s
1、编写流水线步骤
上面的就是凭证ID名称的来源,要保持一致
2、给每个微服务准备一个deployment.yml文件:
yaml文件内容如下:
apiVersion: apps/v1 kind: Deployment metadata: labels: app: ruoyi-auth name: ruoyi-auth namespace: ormis #一定要写名称空间 spec: progressDeadlineSeconds: 600 replicas: 1 selector: matchLabels: app: ruoyi-auth strategy: rollingUpdate: maxSurge: 50% maxUnavailable: 50% type: RollingUpdate template: metadata: labels: app: ruoyi-auth spec: imagePullSecrets: - name: kgf-aliyun-hub #提前在项目下配置访问阿里云的账号密码 containers: - image: $REGISTRY/$DOCKERHUB_NAMESPACE/ruoyi-auth:SNAPSHOT-$BUILD_NUMBER imagePullPolicy: Always name: ruoyi-auth ports: - containerPort: 8080 protocol: TCP resources: limits: cpu: 300m memory: 600Mi terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always terminationGracePeriodSeconds: 30 --- apiVersion: v1 kind: Service metadata: labels: app: ruoyi-auth name: ruoyi-auth namespace: ormis spec: ports: - name: http port: 8080 protocol: TCP targetPort: 8080 selector: app: ruoyi-auth sessionAffinity: None type: ClusterIP
上面的kgf-aliyun-hub凭证要提前在项目中建好:
3、下面我们运行流水线测试一下看看是否可以部署成功
修改一下Jenkinsfile文件:
再次部署:
成功,下面到项目中看一下:
4、下面我们将其他几个服务创建并行部署
我们先简单创建一个模板:
直接编辑Jenkinsfile文件:
5、点击运行测试
后端全部部署成功!
七、开始定义流水线之部署前端项目到k8s
1、创建前端服务的流水线
如果指定路径下存在Jenkinsfile,将会为我们自动创建流水线
2、查看应用负载
创建一个对外的svc
访问:
访问成功:
3、前端用到的相关配置文件
3.1、deploy.yaml
内容如下:
apiVersion: apps/v1 kind: Deployment metadata: labels: app: ruoyi-ui name: ruoyi-ui namespace: ormis #一定要写名称空间 spec: progressDeadlineSeconds: 600 replicas: 1 selector: matchLabels: app: ruoyi-ui strategy: rollingUpdate: maxSurge: 50% maxUnavailable: 50% type: RollingUpdate template: metadata: labels: app: ruoyi-ui spec: imagePullSecrets: - name: kgf-aliyun-hub #提前在项目下配置访问阿里云的账号密码 containers: - image: $REGISTRY/$DOCKERHUB_NAMESPACE/ruoyi-ui:SNAPSHOT-$BUILD_NUMBER imagePullPolicy: Always name: ruoyi-ui ports: - containerPort: 8080 protocol: TCP resources: limits: cpu: 300m memory: 600Mi terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always terminationGracePeriodSeconds: 30 --- apiVersion: v1 kind: Service metadata: labels: app: ruoyi-ui name: ruoyi-ui namespace: ormis spec: ports: - name: http port: 8080 protocol: TCP targetPort: 8080 selector: app: ruoyi-ui sessionAffinity: None type: ClusterIP
3.2、Jenkinsfile文件
内容如下:
pipeline { agent { node { label 'nodejs' } } stages { stage('拉取代码') { agent none steps { container('nodejs') { git(url: 'https://gitee.com/kgf897570/ruoyi-cloud.git', credentialsId: 'ruoyi-cloud-gitee', branch: 'master', changelog: true, poll: false) sh 'ls -al ruoyi-ui/' } } } stage('项目编译') { agent none steps { container('nodejs') { sh 'ls -l' sh 'cd ruoyi-ui/ && ls -al' sh 'cd ruoyi-ui/ && npm install --registry=https://registry.npm.taobao.org' sh 'cd ruoyi-ui/ && ls -al && npm run build:prod' sh 'cd ruoyi-ui/ && ls -al' } } } stage('构建镜像') { agent none steps { container('nodejs') { sh 'ls' sh 'docker build -t ruoyi-ui:latest -f ruoyi-ui/Dockerfile ./ruoyi-ui' } } } stage('推送镜像') { agent none steps { container('nodejs') { withCredentials([usernamePassword(credentialsId : 'aliyu-ruoyi' ,usernameVariable : 'DOCKER_USER_VAR' ,passwordVariable : 'DOCKER_PWD_VAR' ,)]) { sh 'echo "$DOCKER_PWD_VAR" | docker login $REGISTRY -u "$DOCKER_USER_VAR" --password-stdin' sh 'docker tag ruoyi-ui:latest $REGISTRY/$DOCKERHUB_NAMESPACE/ruoyi-ui:SNAPSHOT-$BUILD_NUMBER' sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/ruoyi-ui:SNAPSHOT-$BUILD_NUMBER' } } } } stage('部署到dev环境') { agent none steps { kubernetesDeploy(configs: 'ruoyi-ui/deploy/**', enableConfigSubstitution: true, kubeconfigId: 'demo-kubeconfig') } } } environment { DOCKER_CREDENTIAL_ID = 'dockerhub-id' GITHUB_CREDENTIAL_ID = 'github-id' KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig' REGISTRY = 'registry.cn-zhangjiakou.aliyuncs.com' DOCKERHUB_NAMESPACE = 'kgf-ruoyi' ALIYUNHUB_NAMESPACE = 'kgf-ruoyi' GITHUB_ACCOUNT = 'kubesphere' APP_NAME = 'devops-java-sample' } }
3.3、Dockerfile文件
内容如下:
# 基础镜像 FROM nginx # author MAINTAINER ruoyi # 挂载目录 VOLUME /home/ruoyi/projects/ruoyi-ui # 创建目录 RUN mkdir -p /home/ruoyi/projects/ruoyi-ui # 指定路径 WORKDIR /home/ruoyi/projects/ruoyi-ui # 复制conf文件到路径 COPY ./nginx/conf/nginx.conf /etc/nginx/nginx.conf # 复制html文件到路径 COPY ./dist /home/ruoyi/projects/ruoyi-ui
3.4、nginx.conf文件
内容如下:
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name _; location / { root /home/ruoyi/projects/ruoyi-ui; try_files $uri $uri/ /index.html; index index.html index.htm; } location /prod-api/{ proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://ruoyi-gateway-svc.ormis:8080/; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }# requirepass 123456