DevOps基础
DevOps(Development和Operations的组合词)
operate
v.
操纵,操作(机器或设备);(机器等)运转,运行 ;管理,经营(企业、部门等);
operation
n.
运作,实施;运转,操作;手术;(有组织的)活动,行动;军事行动;企业,公司;业务,经营 ;(数学)运算
1、DevOps简介
DevOps 是一系列做法和工具,可以使 IT 和软件开发团队之间的流程实现自动化。其中,随着敏捷软件开发日趋流行,持续集成 (CI) 和持续交付 (CD) 已经成为该领域一个理想的解决方案。在 CI/CD 工作流中,每次集成都通过自动化构建来验证,包括编码、发布和测试,从而帮助开发者提前发现集成错误,团队也可以快速、安全、可靠地将内部软件交付到生产环境。
- 整合 sonarQube 代码质量分析
continuous integration 持续集成
- build 构建
- test 测试
- merge 合并
continue
英
/kənˈtɪnjuː/
v.
(使)继续,(使)延续;继续说,接着说;移动,延伸;留任,维持原状
delivery 持续交付
- automatically 自动的
- release to
- repository 自动发布到仓库
deployment 持续部署
- deploy to
- production
delivery
英
/dɪˈlɪvəri/
n.
递送,投递;递送物;演讲风格,演说方式;分娩,生产;投球方式
adj.
运送的
automatically
英
/ˌɔːtəˈmætɪkli/
adv.
自然地,必然地;不假思索地,无意识地;自动地
2、DevOps落地
https://kubesphere.com.cn/docs/devops-user-guide/understand-and-manage-devops-projects/overview/
1、内置的Agent
https://kubesphere.com.cn/docs/devops-user-guide/how-to-use/choose-jenkins-agent/
尚医通项目上云
1、项目架构
yygh-parent
|---common //通用模块
|---hospital-manage //医院后台 [9999]
|---model //数据模型
|---server-gateway //网关 [80]
|---service //微服务层
|-------service-cmn //公共服务 [8202]
|-------service-hosp //医院数据服务 [8201]
|-------service-order //预约下单服务 [8206]
|-------service-oss //对象存储服务 [8205]
|-------service-sms //短信服务 [8204]
|-------service-statistics //统计服务 [8208]
|-------service-task //定时服务 [8207]
|-------service-user //会员服务 [8203]
====================================================================
yygh-admin //医院管理后台 [9528]
yygh-site //挂号平台 [3000]
2、中间件
中间件 | 集群内地址 | 外部访问地址 |
---|---|---|
Nacos | his-nacos.his:8848 | http://139.198.165.238:30349/nacos |
MySQL | his-mysql.his:3306 | 139.198.165.238:31840 |
Redis | his-redis.his:6379 | 139.198.165.238:31968 |
Sentinel | his-sentinel.his:8080 | http://139.198.165.238:31523/ |
MongoDB | mongodb.his:27017 | 139.198.165.238:32693 |
RabbitMQ | rabbitm-yp1tx4-rabbitmq.his:5672 | 139.198.165.238:30375 |
ElasticSearch | his-es.his:9200 | 139.198.165.238:31300 |
部署sentinel
-
名字:his-sentinel
-
leifengyang/sentinel:1.8.2
- 端口为:TCP,8080
-
同步主机时区,其他都不用选:
-
创建 NodePort 类型的svc
-
his-sentinel-node
-
其他提醒:sentinel 可以连接上 nacos,流控规则 在配置中心配置
部署MongoDB
-
已经使用比特纳米仓库 bitnami
- 搜 mongodb,一键部署即可。
- 版本:老师的为,10.26.0(4.4.8)
-
部署新应用,来自应用模板,bitnami
- 随便部署13.6.3 [6.0.3],都部署不成功。
- 关闭账号密码的访问。
- 持久化部署,默认8G,可以调小点。
-
使用有状态副本,部署成功了。
- 挂载一下 数据卷,其他的没配置。
docker run -d \
-p 27017:27017 \
--name example-mongo \
-v mongo-data:/data/db \
mongo:latest
- 创建svc,外部暴露,his-mongo-node
- 端口 为 27017
导入msql 和 创建配置
-
导入\yygh-parent-master\data\sql
-
登录http://172.31.0.10:32470/nacos/
-
创建配置:相关的配置文件,和 项目名字一样,+ prod
-
注意,因为 docker打包时 未设置名称空间。
- 配置文件都建立在 public下。
-
service-cmn-prod.yml
-
复制 项目下的:application-dev.yml
- 端口改不改都行,docker 启动会指定。
- 更改 sentinel 的访问地址。his-sentinel.his:8080
- http:// 前缀留着
- redis的也要改:his-redis.his:6379
- 数据库的访问地址:his-mysql.his:3306
server: port: 8202 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath:mapper/*.xml global-config: db-config: logic-delete-value: 1 logic-not-delete-value: 0 spring: cloud: sentinel: transport: dashboard: http://his-sentinel.his:8080 redis: host: his-redis.his port: 6379 database: 0 timeout: 1800000 password: lettuce: pool: max-active: 20 #最大连接数 max-wait: -1 #最大阻塞等待时间(负数表示没限制) max-idle: 5 #最大空闲 min-idle: 0 #最小空闲 datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://his-mysql.his:3306/yygh_cmn?characterEncoding=utf-8&useSSL=false username: root password: 123456 hikari: connection-test-query: SELECT 1 connection-timeout: 60000 idle-timeout: 500000 max-lifetime: 540000 maximum-pool-size: 12 minimum-idle: 10 pool-name: GuliHikariPool jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8
-
-
service-hosp
-
service-order
-
service-oss
-
service-sms
-
service-statistics
-
service-task
- 注意这个:sentinel 要加 http://
-
service-user
-
server-gateway 网关的所有配置
-
hospital-manage 是单体应用,不连nacos,直接改。
3、流水线
创建devops项目
- 登录 pm-wang
- 创建 his-devops
- 邀请 dev-zhao,为 admin
- DevOps 工程管理员,可以管理 DevOps 工程下所有的资源。
- 邀请 dev-liu,为operator
- DevOps 工程普通成员,可以在 DevOps 工程下创建流水线凭证等。
- 还有角色:viewer DevOps 工程观察者,可以查看 DevOps 工程下所有的资源。
- 邀请 dev-zhao,为 admin
Jenkins
https://www.jenkins.io/zh/doc/book/pipeline/
-
登录 dev-zhao,即可创建流水线
- 名称为:yygh-parent-devops
- 其他都不创建,
- 点击编辑流水线:选择中间的 ci/cd
- 点击保存
- 之后在点击 编辑jenkins 流水线。
- 即可得到一个 模板。
- 名称为:yygh-parent-devops
-
编辑流水线,可以看到4个 Agent
- base
- go
- maven
- nodejs
- 官网地址
-
jenkins和k8s一样,都是 主节点,控制node 节点,构建流水线。
编辑流水线
每一步执行完 都可添加一个shell
- echo ‘xx 执行成功了,哈哈’
第一步 拉取代码
- 第一步输入名称,拉取代码
- 删除原来的流程。指定容器 填 maven
- 添加嵌套步骤,选择 git
- 填入 url (点击克隆那个url .git结尾),用户名,密码,和分支 master
- 添加嵌套步骤,选择 shell,输入 ls -al
第二步 项目编译
-
点 第二步 名称 项目编译
-
任务:指定容器,maven
-
添加嵌套步骤shell:ls
-
在添加嵌套shell:
mvn clean package -Dmaven.test.skip=true
-
-
配置 阿里云 仓库。
- 登录 admin 账户
- 集群管理——配置中心——配置
- 找到 ks-devops-agent,修改
- 在 mirrors 标签里
<mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> <!-- central --> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror>
-
下面这里,也进行了说明:修改maven让他从阿里云下载镜像
第三步 制作镜像
-
输入步骤名
-
指定容器,maven (maven容器里有 docker,其他也是)
-
添加一个shell为:ls hospital-manage/target/ 看下有没有jar
-
添加shell
docker build -t hospital-manage:lastest -f hospital-manage/Dockerfile ./hospital-manage/
-
添加并行阶段,每个微服务 并发构建镜像。(此时会增加标签parallel {})
-
复制Jenkins文件,自己去 复制粘贴的改。
- 注意:service-cmn 和 相同的服务,都多加了 一层 service
stage('default-2') {
parallel {
stage('构建hospital-manage镜像') {
agent none
steps {
container('maven') {
sh 'ls hospital-manage/target'
sh 'docker build -t hospital-manage:latest -f hospital-manage/Dockerfile ./hospital-manage/'
}
}
}
stage('构建service-cmn镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-cmn/target'
sh 'docker build -t service-cmn:latest -f service/service-cmn/Dockerfile ./service/service-cmn/'
}
}
}
}
第四步 推送XX镜像
-
名字改为推送镜像,添加个并行
-
添加凭证——新建凭证aliyun-docker-registry
- 密码变量:DOCKER_PWD_VAR
- 用户名变量:DOCKER_USER_VAR
- 在凭证里 选择嵌套步骤,随便添加一个 shell:ls,去idea里修改。
-
环境变量分析1
# 仓库名
REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
DOCKERHUB_NAMESPACE = 'sgg_his'
#要推送的地址
//docker push registry.cn-hangzhou.aliyuncs.com/sgg_his/ruoyi-system:[镜像版本号]
//docker tag hospital-manage:lastest registry.cn-hangzhou.aliyuncs.com/sgg_his/hospital-manage:SNAPSHOT-13
sh 'docker tag hospital-manage:lastest $REGISTRY/$DOCKERHUB_NAMESPACE/hospitalmanage:SNAPSHOT-$BUILD_NUMBER'
#BUILD_NUMBER 每次构建的版本号
- 环境变量分析2
- 增加了 并行,就会出这个标签 parallel
- 增加了 凭证,就会出这个标签 withCredentials
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,usernameVariable : 'DOCKER_USER_VAR' ,passwordVariable : 'DOCKER_PWD_VAR' ,)]) {
# sh 'docker login --username=$DOCKER_USER_VAR $REGISTRY'
# 输出密码 | 登录时 --password-stdin,输出。
sh 'echo "$DOCKER_PWD_VAR" | docker login $REGISTRY -u "$DOCKER_USER_VAR" --password-stdin'
sh 'docker tag hospital-manage:lastest $REGISTRY/$DOCKERHUB_NAMESPACE/hospital-manage:SNAPSHOT-$BUILD_NUMBER'
# 推送,就是上面的
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/hospital-manage:SNAPSHOT-$BUILD_NUMBER'
}
- 下面还有完整的 例子。
- 之后:hospital-manage,会推送到 阿里云。
- 复制多份 推送其他镜像。
第五步 部署到dev环境
- 任务,默认添加一个 审核,需要人工点
- @dev-liu 请确认。 @别人,可以让他点击。
寻找k8s文件
-
node节点,不能用 kubectl ,因为没有配置文件。所以 不配置 node也没法部署。
- /root/.kube/config
-
进行配置:
-
默认创建了一个任务 kubernetesDeploy,点击编辑,点新建凭证,已经给配置好了,k8s的相关配置。
-
填入凭证ID,demo-kubeconfig,是在 Jenkins 的环境变量里 看到的。
KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
-
配置文件路径:这是项目的,如:hospital-manage/deploy/**
- 里面是部署k8s的文件,即可 部署这个项目。
-
-
添加并行任务,然后复制到 idea,复制多份,进行更改。
k8s中的阿里密钥
-
选中 his 项目——配置中心——密钥
- 名字为:aliyun-docker-hub,选择:镜像仓库密钥,仓库地址:registry.cn-hangzhou.aliyuncs.com
- 用户名,密码,然后验证一下。
- 名字为:aliyun-docker-hub,选择:镜像仓库密钥,仓库地址:registry.cn-hangzhou.aliyuncs.com
-
# 对应k8s的配置 spec: imagePullSecrets: - name: aliyun-docker-hub #提前在项目下配置访问阿里云的账号密码
流水线文件的取值 bug
-
解决bug,取值的问题,去掉 “$KUBECONFIG_CREDENTIAL_ID” 两边的 单引号。
-
kubernetesDeploy(configs: 'hospital-manage/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
k8s中的写的 名称空间
- 解决bug,registry.cn-hangzhou.aliyuncs.com/$ALIYUNHUB_NAMESPACE/hospital-manage:SNAPSHOT-6
- $ALIYUNHUB_NAMESPACE 未取到值
- 这是在 deploy.yml k8s的配置文件中指定的。
- 在:Jenkins 里面添加这个文件:就是命名空间配置。
都加上 redis
-
给每个容器的配置文件,加上 redis的配置,有些项目会默认连 本机的 redis。(如:oss项目)
-
spring: redis: host: his-redis.his port: 6379
k8s配置文件
- hospital-manage/deploy/
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: hospital-manage
name: hospital-manage
namespace: his #一定要写名称空间,这里就是 我们kubesphere 创建的项目名,底层是 k8s的namespace对应
spec:
progressDeadlineSeconds: 600
replicas: 1
selector:
matchLabels:
app: hospital-manage
strategy:
rollingUpdate:
maxSurge: 50%
maxUnavailable: 50%
type: RollingUpdate
template:
metadata:
labels:
app: hospital-manage
spec:
imagePullSecrets:
- name: aliyun-docker-hub #提前在项目下配置访问阿里云的账号密码
containers:
- image: $REGISTRY/$ALIYUNHUB_NAMESPACE/hospital-manage:SNAPSHOT-$BUILD_NUMBER
# readinessProbe:
# httpGet:
# path: /actuator/health
# port: 8080
# timeoutSeconds: 10
# failureThreshold: 30
# periodSeconds: 5
imagePullPolicy: Always
name: app
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: hospital-manage
name: hospital-manage
namespace: his
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: hospital-manage
sessionAffinity: None
type: ClusterIP
完整Jenkinsfile
- 在父目录下(和子目录统计) 和 创建Jenkinsfile
//官方的文件。
pipeline {
agent any //和 集群工作有关,不管。
stages {
stage('Build') {
steps {
}
}
stage('Test') {
steps {
}
}
stage('Deploy') {
steps {
}
}
}
}
pipeline {
agent {
node {
label 'maven'
}
}
stages {
stage('拉取代码') {
agent none
steps {
container('maven') {
git(url: 'https://gitee.com/leifengyang/yygh-parent.git', credentialsId: 'gitee-id', branch: 'master', changelog: true, poll: false)
sh 'ls -al'
}
}
}
stage('项目编译') {
agent none
steps {
container('maven') {
sh 'ls'
sh 'mvn clean package -Dmaven.test.skip=true'
sh 'ls hospital-manage/target'
}
}
}
stage('default-2') {
parallel {
stage('构建hospital-manage镜像') {
agent none
steps {
container('maven') {
sh 'ls hospital-manage/target'
sh 'docker build -t hospital-manage:latest -f hospital-manage/Dockerfile ./hospital-manage/'
}
}
}
stage('构建server-gateway镜像') {
agent none
steps {
container('maven') {
sh 'ls server-gateway/target'
sh 'docker build -t server-gateway:latest -f server-gateway/Dockerfile ./server-gateway/'
}
}
}
stage('构建service-cmn镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-cmn/target'
sh 'docker build -t service-cmn:latest -f service/service-cmn/Dockerfile ./service/service-cmn/'
}
}
}
stage('构建service-hosp镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-hosp/target'
sh 'docker build -t service-hosp:latest -f service/service-hosp/Dockerfile ./service/service-hosp/'
}
}
}
stage('构建service-order镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-order/target'
sh 'docker build -t service-order:latest -f service/service-order/Dockerfile ./service/service-order/'
}
}
}
stage('构建service-oss镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-oss/target'
sh 'docker build -t service-oss:latest -f service/service-oss/Dockerfile ./service/service-oss/'
}
}
}
stage('构建service-sms镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-sms/target'
sh 'docker build -t service-sms:latest -f service/service-sms/Dockerfile ./service/service-sms/'
}
}
}
stage('构建service-statistics镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-statistics/target'
sh 'docker build -t service-statistics:latest -f service/service-statistics/Dockerfile ./service/service-statistics/'
}
}
}
stage('构建service-task镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-task/target'
sh 'docker build -t service-task:latest -f service/service-task/Dockerfile ./service/service-task/'
}
}
}
stage('构建service-user镜像') {
agent none
steps {
container('maven') {
sh 'ls service/service-user/target'
sh 'docker build -t service-user:latest -f service/service-user/Dockerfile ./service/service-user/'
}
}
}
}
}
stage('default-3') {
parallel {
stage('推送hospital-manage镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 hospital-manage:latest $REGISTRY/$DOCKERHUB_NAMESPACE/hospital-manage:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/hospital-manage:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送server-gateway镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 server-gateway:latest $REGISTRY/$DOCKERHUB_NAMESPACE/server-gateway:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/server-gateway:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送service-cmn镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 service-cmn:latest $REGISTRY/$DOCKERHUB_NAMESPACE/service-cmn:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/service-cmn:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送service-hosp镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 service-hosp:latest $REGISTRY/$DOCKERHUB_NAMESPACE/service-hosp:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/service-hosp:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送service-order镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 service-order:latest $REGISTRY/$DOCKERHUB_NAMESPACE/service-order:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/service-order:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送service-oss镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 service-oss:latest $REGISTRY/$DOCKERHUB_NAMESPACE/service-oss:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/service-oss:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送service-sms镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 service-sms:latest $REGISTRY/$DOCKERHUB_NAMESPACE/service-sms:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/service-sms:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送service-statistics镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 service-statistics:latest $REGISTRY/$DOCKERHUB_NAMESPACE/service-statistics:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/service-statistics:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送service-task镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 service-task:latest $REGISTRY/$DOCKERHUB_NAMESPACE/service-task:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/service-task:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('推送service-user镜像') {
agent none
steps {
container('maven') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 service-user:latest $REGISTRY/$DOCKERHUB_NAMESPACE/service-user:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/service-user:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
}
}
stage('default-4') {
parallel {
stage('hospital-manage - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'hospital-manage/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('server-gateway - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'server-gateway/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('service-cmn - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'service/service-cmn/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('service-hosp - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'service/service-hosp/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('service-order - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'service/service-order/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('service-oss - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'service/service-oss/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('service-sms - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'service/service-sms/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('service-statistics - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'service/service-statistics/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('service-task - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'service/service-task/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('service-user - 部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'service/service-user/deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
}
}
//1、配置全系统的邮件: 全系统的监控
//2、修改ks-jenkins的配置,里面的邮件; 流水线发邮件
stage('发送确认邮件') {
agent none
steps {
mail(to: '17512080612@163.com', subject: '构建结果', body: "构建成功了 $BUILD_NUMBER")
}
}
}
environment {
DOCKER_CREDENTIAL_ID = 'dockerhub-id'
GITHUB_CREDENTIAL_ID = 'github-id'
KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
DOCKERHUB_NAMESPACE = 'lfy_hello'
GITHUB_ACCOUNT = 'kubesphere'
APP_NAME = 'devops-java-sample'
ALIYUNHUB_NAMESPACE = 'lfy_hello'
}
parameters {
string(name: 'TAG_NAME', defaultValue: '', description: '')
}
}
1、项目地址
https://gitee.com/leifengyang/yygh-parent
https://gitee.com/leifengyang/yygh-admin
https://gitee.com/leifengyang/yygh-site
2、项目默认规则
- 每个微服务项目,在生产环境时,会自动获取
微服务名-prod.yml
作为自己的核心配置文件 - 每个微服务项目,在生产环境时,默认都是使用
8080
端口
3、生产与开发配置隔离
4、deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: service-cart
name: service-cart
namespace: his #一定要写名称空间
spec:
progressDeadlineSeconds: 600
replicas: 1
selector:
matchLabels:
app: service-cart
strategy:
rollingUpdate:
maxSurge: 50%
maxUnavailable: 50%
type: RollingUpdate
template:
metadata:
labels:
app: service-cart
spec:
imagePullSecrets:
- name: aliyun-docker-hub #提前在项目下配置访问阿里云的账号密码
containers:
- image: $REGISTRY/$ALIYUNHUB_NAMESPACE/service-cart
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
timeoutSeconds: 10
failureThreshold: 30
periodSeconds: 5
imagePullPolicy: Always
name: app
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: service-cart
name: service-cart
namespace: his
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: service-cart
sessionAffinity: None
type: ClusterIP
4、devops实战
1、修改maven让他从阿里云下载镜像
-
使用admin登陆ks
-
进入集群管理
-
进入配置中心
-
找到配置
-
- ks-devops-agent
- 修改这个配置。加入maven阿里云镜像加速地址
2、缓存机制
已经下载过的jar包,下一次流水线的启动,不会重复下载
3、部署到k8s集群
-
给每一个微服务准备一个 deploy.yaml(k8s的部署配置文件)
-
执行以下步骤
-
-
传入 deploy.yaml 的位置就能部署
-
- kubectl apply -f xxxx
-
一定在项目里面(his,不是流水线项目),找到配置–密钥,配置一个阿里云的访问账号密码
-
其他问题
内存不够排错
-
排错:kubectl get pod -A | grep maven
-
kubectl describe pod -n xxx pod的名
- 看到日志,调度失败,3个节点,一个主节点不能用。
- 剩下的两个节点,内存不够。
-
kubectl top pods -A
-
kubectl top nodes
logback文件更改
- pro改为 prod,读取的也是 spring.profile.active: prod
<!--生产环境:输出到文件-->
<springProfile name="prod">
进入容器日志排错
-
修改配置模板,取消探针。
-
容器内,也创建了 目录。进入:C:目录,即可看到。
<property name="log.path" value="C:/gmall_log/user" />
-
bootstrap.properties 去掉乱码
-
xml 增加 nacos 配置中心的配置
-
logback-spring.xml增加 控制台日志
<!--生产环境:输出到文件--> <springProfile name="prod"> <!--可以输出项目中的debug日志,包括mybatis的sql日志--> <logger name="com.guli" level="WARN" /> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="WARN_FILE" /> </root> </springProfile>
-
配置中心 都打印 展示节点 详细信息。打印详细,就没问题了。
management: endpoints: web: exposure: include: "*" endpoint: health: show-details: always
- 访问:curl ip:8080/actuator/health
- 明白了,因为 微服务,并没有暴露这个接口,然后 k8s 还有 探针,不挂才怪。
-
之后还是失败,但是 手动请求一下8080端口,就自动好了。
-
service-user-prod 配置中心的,要删除 配置的端口
-
k8s 配置文件,取消就绪探针
# readinessProbe: # httpGet: # path: /actuator/health # port: 8080 # timeoutSeconds: 10 # failureThreshold: 30 # periodSeconds: 5
全系统邮件配置
-
添加邮件,收件人,抄送,主题:构建结果
- Body:构建成功了,$BUILD_NUMBER
-
登录163,设置 POP3,SMTP,IMAP
- 点击 开启 POP3/SMTP 发送短信,获取授权码(就是SMTP密码),
- 使用设备,随便填,如:ks
-
登录admin
- 平台设置——通知设置——填入
- SMTP 服务器地址 smtp.163.com
- SMTP 密码,就是授权码
- SMTP 就是 邮件登录名
- 发件邮箱,同样 是登录名
- 接收邮箱,同样也 填入一个 登录名。
- 平台设置——通知设置——填入
流水线邮件配置
https://kubesphere.io/zh/docs/v3.3/devops-user-guide/how-to-use/pipelines/jenkins-email/
转到应用负载下的工作负载,然后从下拉列表中选择 kubesphere-devops-system 项目。点击 devops-jenkins
右侧的 并选择编辑 YAML 以编辑其 YAML 配置文件。
-
环境变量名称 描述信息 EMAIL_SMTP_HOST SMTP 服务器地址 EMAIL_SMTP_PORT SMTP 服务器端口(如:25) EMAIL_FROM_ADDR 电子邮件发件人地址 EMAIL_FROM_NAME 电子邮件发件人姓名 EMAIL_FROM_PASS 电子邮件发件人密码 EMAIL_USE_SSL 是否启用 SSL 配置
- 登录admin——集群管理——应用负载——工作负载
- 名称为:ks-jenkins ,项目为:kubesphere-devops-system
- 端口:SMTP,非SSL用25,SSL 用:465/994
- $BUILD_NUMBER 取值失败,修改Jenkins yaml
- 是因为使用的是 单引号,需要用 双引号,才能取出。
4、前端项目
1、yygh-admin
npm run build
会生成dist
目录,放到nginx的html下,即可运行
2、yygh-site
-
npm install --registry=https://registry.npm.taobao.org
安装项目依赖 -
npm run build
对项目打包, -
打包完成后把
.nuxt ,static, nuxt.config.js, package.json
这四个关键文件复制到node
环境。先npm install
再使用npm run start
即可运行
3、思考
-
admin的镜像和site的镜像大小为何差距那么大?
-
- 如何对镜像进行瘦身?
-
yygh-site 有1.08G
- 因为是Nuxt 项目,服务端 打包编译, “npm”,“run”,“build”
- 相当于 maven仓库里 下载了很多东西。
- 而最终 打包后,是 html,如果只用 nginx + html 肯定会小很多。
-
yygh-admin 有136M
医院挂号后台打包
npm install --registry=https://registry.npm.taobao.org #两个前端项目同样的打包
- 网关项目暴露外网端口,yygh-admin-master项目更改dev.env.js 文件,更改地址。
npm run dev #同样的运行
-
yygh-site-master项目更改为:request.js
-
使用vue.js 编译后npm run build,放到 nginx 就能运行。
- COPY dist /usr/share/nginx/html/
导入mongoDB的数据
- Department.json
- Hospital.json
- Schedule.json
医院挂号后台 流水线
pipeline {
agent {
node {
label 'nodejs'
}
}
stages {
stage('拉取代码') {
agent none
steps {
container('nodejs') {
git(url: 'https://gitee.com/leifengyang/yygh-admin.git', credentialsId: 'gitee-id', branch: 'master', changelog: true, poll: false)
sh 'ls -al'
}
}
}
stage('项目编译') {
agent none
steps {
container('nodejs') {
sh 'npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/'
sh 'npm install --registry=https://registry.npm.taobao.org'
sh 'npm run build'
sh 'ls'
}
}
}
stage('构建镜像') {
agent none
steps {
container('nodejs') {
sh 'ls'
//拉取后,已经是当前目录了
sh 'docker build -t yygh-admin:latest -f Dockerfile .'
}
}
}
stage('推送镜像') {
agent none
steps {
container('nodejs') {
withCredentials([usernamePassword(credentialsId : 'aliyun-docker-registry' ,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 yygh-admin:latest $REGISTRY/$DOCKERHUB_NAMESPACE/yygh-admin:SNAPSHOT-$BUILD_NUMBER'
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/yygh-admin:SNAPSHOT-$BUILD_NUMBER'
}
}
}
}
stage('部署到dev环境') {
agent none
steps {
kubernetesDeploy(configs: 'deploy/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
//1、配置全系统的邮件: 全系统的监控
//2、修改ks-jenkins的配置,里面的邮件; 流水线发邮件
stage('发送确认邮件') {
agent none
steps {
mail(to: '17512080612@163.com', subject: 'yygh-admin构建结果', body: "构建成功了 $BUILD_NUMBER")
}
}
}
environment {
DOCKER_CREDENTIAL_ID = 'dockerhub-id'
GITHUB_CREDENTIAL_ID = 'github-id'
KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
DOCKERHUB_NAMESPACE = 'lfy_hello'
GITHUB_ACCOUNT = 'kubesphere'
APP_NAME = 'devops-java-sample'
ALIYUNHUB_NAMESPACE = 'lfy_hello'
}
}
医院挂号后台Dockerfile
FROM nginx
#将dist目录内容复制到nginx容器html内部
COPY dist /usr/share/nginx/html/
EXPOSE 80
医院挂号后台k8s文件
-
deploy/deploy.yml
apiVersion: apps/v1 kind: Deployment metadata: labels: app: yygh-admin name: yygh-admin namespace: his #一定要写名称空间 spec: progressDeadlineSeconds: 600 replicas: 1 selector: matchLabels: app: yygh-admin strategy: rollingUpdate: maxSurge: 50% maxUnavailable: 50% type: RollingUpdate template: metadata: labels: app: yygh-admin spec: imagePullSecrets: - name: aliyun-docker-hub #提前在项目下配置访问阿里云的账号密码 containers: - image: $REGISTRY/$ALIYUNHUB_NAMESPACE/yygh-admin:SNAPSHOT-$BUILD_NUMBER # readinessProbe: # httpGet: # path: /actuator/health # port: 8080 # timeoutSeconds: 10 # failureThreshold: 30 # periodSeconds: 5 imagePullPolicy: Always name: app ports: - containerPort: 80 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: yygh-admin name: yygh-admin namespace: his spec: ports: - name: http port: 80 protocol: TCP targetPort: 80 nodePort: 32248 selector: app: yygh-admin sessionAffinity: None type: NodePort
git命令
git add .
git status
git commit -m 修改了内容
git push
新建DevOps
-
名字为:yygh-admin,
-
选择一个代码仓库,选择 git,使用 码云的凭证,输入仓库的URL
-
脚本路径:Jenkinsfile 和 项目根目录的是同一个文件。
-
node-sass 去淘宝安装
npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
医院挂号用户端
使用:Nuxt.js 是一个基于 Vue.js 的通用应用框架。
- Nuxt 编写。服务端 渲染技术。
npm run dev #同样的运行,本地启动
- 默认监听为 localhost 的3000
Dockerfile
FROM node:14.17.6
WORKDIR /app
#把.nuxt目录下的所有内容复制到/app/.nuxt/
COPY . /app/
#安装核心依赖 npm cache clean -f
RUN ["npm","install","--registry=https://registry.npm.taobao.org"]
RUN ["npm","run","build"]
EXPOSE 3000
CMD ["npm", "run", "start"] #nuxt 依服务器的方式,在3000端口启动。
改为网关的端口
- request.js
// 创建axios实例
const service = axios.create({
baseURL: 'http://139.198.165.238:32607', //生产环境
timeout: 15000 // 请求超时时间
})
创建流水线
- yygh-site 医院挂号的用户端
- git仓库,选择地址 和 凭证。
修改 nuxt 暴露的端口
-
如果不改:外网访问,访问到后 跳转为 localhost,就会拒绝。
-
package.json,默认是 localhost:3000。改为了 本机地址:3000
"config": {
"nuxt": {
"host": "0.0.0.0",
"port": "3000"
}
},
网关的 k8s更改
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: 8080
nodePort: 32607 #外网暴露的端口 定死。
selector:
app: server-gateway
sessionAffinity: None
type: NodePort #改为nodePort
5、webhook
-
就是 选择 流水线,使用 仓库的地址,最后一步,会有一个 webhook
-
1、每个项目,都有流水线文件
-
2、每次修改完项目,手动点击运行
-
3、希望,每次修改完项目,代码推送,流水线能自动运行
-
- 写代码并提交------> gitee ---------> 给指定的地方发请求(webhook)------> kubesphere平台感知到 -----> 自动启动流水线继续运行
- http://139.198.165.238:30880/devops_webhook/git/?url=https://gitee.com/leifengyang/yygh-admin.git
优化
前端项目都用固定的端口
- 挂号用户端
spec:
ports:
- name: http
port: 3000
protocol: TCP
targetPort: 3000
nodePort: 32070
selector:
app: yygh-site
sessionAffinity: None
type: NodePort
- 医院挂号管理系统
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
nodePort: 32248
selector:
app: yygh-admin
sessionAffinity: None
type: NodePort
- 前端项目 可以多部署几份,前置 在放个 ingress 网络,也可以自己装 nginx
先创建一个流水线,编辑流程
-
流水线 编辑后,在创建一个 从仓库拉取的 项目(会带 webhook)
-
然后用 上面编辑的流程流水线 ,进行替换。
后续知识
- service mesh 服务网格
- Istio 落地技术
- Istio是一个Service Mesh形态的用于服务治理的开放平台
- 普罗米修斯 promethes 集群监控和告警
- Grafana 监控面板。
- Grafana是一款用Go语言开发的.源数据可视化工具,可以做数据监控和数据统计,带有告警功能。
KubeKey介绍
部署高可用Kubernetes集群
KubeKey集群配置文件详解
Kubernetes增删集群节点
Kubernetes集群证书管理:证书 一年内有效。
- kubeSphere 3.2 平台,可以自动续期。
KubeSphere启用可插拔组件
Kubernetes 节点管理
使用Source-to-Image发布应用
使用Binary-to-lmage发布应用
使用Jenkinsfile 创建流水线
ArgoCD 实践
Argo CD简介 Argo CD是一款基于 kubernetes 的声明式的Gitops 持续部署工具。
虚拟化技术介绍
Kubevirt介绍
K8s的专业技术认证主要有以下几种:
- CKA(Kubernetes 管理员认证)
- CKAD(Kubernetes 应用程序开发者认证)
- CKS(Kubernetes 认证安全专家。预计2020年11月开放,须先通过CKA认证)
CKA 证书是云原生计算基金会 CNCF 组织的,
CKA是目前唯一的 Kubernetes 官方认证考试