DevOps
DevOps: Development 和 Operations 的组合
- DevOps 看作开发(软件工程)、技术运营和质量保障(QA)三者的交集。
- 突出重视软件开发人员和运维人员的沟通合作,通过自动化流程来使得软件构建、测试、 发布更加快捷、频繁和可靠。
- DevOps 希望做到的是软件产品交付过程中 IT 工具链的打通,使得各个团队减少时间损耗,更加高效地协同工作。DevOps 能力图如下,良好的闭环可以大大增加整体的产出。
CI/CD
1、持续集成(Continuous Integration)
持续集成是指软件个人研发的部分向软件整体部分交付,频繁进行集成以便更快地发现 其中的错误。“持续集成”源自于极限编程(XP),是 XP 最初的 12 种实践之一。
CI 需要具备这些:
- 全面的自动化测试。这是实践持续集成&持续部署的基础,同时,选择合适的自动化测试工具也极其重要
- 灵活的基础设施。容器,虚拟机的存在让开发人员和 QA 人员不必再大费周折
- 版本控制工具。如 Git,CVS,SVN 等
- 自动化的构建和软件发布流程的工具,如 Jenkins,flow.ci
- 反馈机制。如构建/测试的失败,可以快速地反馈到相关负责人,以尽快解决达到一个更稳定的版本
2、持续交付(Continuous Delivery)
持续交付在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境的「类生产环境」 (production-like environments)中。持续交付优先于整个产品生命周期的软件部署,建立在高水平自动化持续集成之上。
灰度发布。
持续交付和持续集成的优点非常相似:
- 快速发布。能够应对业务需求,并更快地实现软件价值
- 编码->测试->上线->交付的频繁迭代周期缩短,同时获得迅速反馈
- 高质量的软件发布标准。整个交付过程标准化、可重复、可靠
- 整个交付过程进度可视化,方便团队人员了解项目成熟度
- 更先进的团队协作方式。从需求分析、产品的用户体验到交互 设计、开发、测试、运维等角色密切协作,相比于传统的瀑布式软件团队,更少浪费
3、持续部署(Continuous Deployment)
持续部署是指当交付的代码通过评审之后,自动部署到生产环境中。持续部署是持续交付的最高阶段。这意味着,所有通过了一系列的自动化测试的改动都将自动部署到生产环境。它也可以被称为“Continuous Release”。
“开发人员提交代码,持续集成服务器获取代码,执行单元测试,根据测试结果决定是否部署到预演环境,如果成功部署到预演环境,进行整体验收测试,如果测试通过,自动部署到产品环境,全程自动化高效运转。”
持续部署主要好处是,可以相对独立地部署新的功能,并能快速地收集真实用户的反馈。
下图是由 Jams Bowman 绘制的持续交付工具链图
最终部署
kubesphere架构
有状态服务部署
1、有状态服务抽取配置为 ConfigMap
2、有状态服务必须使用 pvc 持久化数据
3、服务集群内访问使用 DNS 提供的稳定域名
1 2 3 4 5 6 7 8
| + 部署流程 + configMap + pvc + 镜像 + 资源限制 + 环境变量 + 挂载pvc + 外网访问、集群内访问等
|
依次部署集群:
MySQL、Redis、RabbitMQ、Elasticsearch、Kibana
Nacos、Zipkin、Nginx、Sentinel
微服务部署
环境准备
1、dockerfile
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
| + 创建项目 dockerfile2、上传项目到服务器。 + 进入项目,构建镜像到本地仓库; + docker build -t nginx:GA-1.0 -f ./Dockerfile . + docker images + docker exec -it 容器 id /bin/bash;进入容器,修改容器 + docker commit -a “leifengyang” -m “nginxxx” 容器 id + docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] + OPTIONS 说明: + -a :提交的镜像作者; + -c :使用 Dockerfile 指令来创建镜像; + -m :提交时的说明文字; + -p :在 commit 时,将容器暂停。 + docker login : 登陆到一个 Docker 镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub + docker login -u 用户名 -p 密码 + docker logout : 登出一个 Docker 镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub + 推送镜像到 docker hub + 标记镜像,docker tag local-image:tagname username/new-repo:tagname + 上传镜像,docker push username/new-repo:tagname + 保存镜像,加载镜像 + 可以保存镜像为 tar,使用 u 盘等设备复制到任意 docker 主机,再次加载镜像 + 保存:docker save spring-boot-docker -o /home/spring-boot-docker.tar + 加载:docker load -i spring-boot-docker.tar + 阿里云操作 + 登录阿里云,密码就是开通镜像仓库时的密码 docker login --username=qwertyuiopasdf_aa registry.cn-hangzhou.aliyuncs.com + 拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/atguigumall/gulimall-nginx:v1.0 + 推送镜像 docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/atguigumall/gulimall-nginx:v1 docker push registry.cn-hangzhou.aliyuncs.com/atguigumall/gulimall-nginx:v1
|
1 2 3 4
| FROM java:openjdk-8-jre-alpine WORKDIR /home COPY target/*.jar /home ENTRYPOINT java -jar *.jar
|
2、k8s部署描述文件
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
| apiVersion: apps/v1 kind: Deployment metadata: labels: app: kubesphere component: ks-sample tier: backend name: ks-sample namespace: kubesphere-sample-prod spec: progressDeadlineSeconds: 600 replicas: 2 selector: matchLabels: app: kubesphere component: ks-sample tier: backend strategy: rollingUpdate: maxSurge: 100% maxUnavailable: 100% type: RollingUpdate template: metadata: labels: app: kubesphere component: ks-sample tier: backend spec: containers: - env: - name: CACHE_IGNORE value: js|html - name: CACHE_PUBLIC_EXPIRATION value: 3d image: $REGISTRY/$HARBOR_NAMESPACE/$APP_NAME:$TAG_NAME readinessProbe: httpGet: path: / port: 8080 timeoutSeconds: 10 failureThreshold: 30 periodSeconds: 5 imagePullPolicy: Always name: ks ports: - containerPort: 8080 protocol: TCP resources: limits: cpu: 300m memory: 600Mi requests: cpu: 100m memory: 100Mi terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always terminationGracePeriodSeconds: 30
|
1 2 3 4 5 6 7 8 9
| + Containerport:容器内服务端口 + TargetPort + pod访问container + Port:集群内service端口,域名、ip端口号 + Nodeport:外部访问集群service + 特点 + Targetport、serviceport端口可以一样 + 每个service、pod地址都不一样,都是集群内虚拟的 + Nodeport不能一样,暴露外部端口
|
3、Jenkinsfile流水线文件
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
| pipeline { agent { node { label 'maven' } }
parameters { string(name:'TAG_NAME',defaultValue: '',description:'') }
environment { DOCKER_CREDENTIAL_ID = 'dockerhub-id' GITHUB_CREDENTIAL_ID = 'github-id' KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig' REGISTRY = 'docker.io' DOCKERHUB_NAMESPACE = '1637872839' GITHUB_ACCOUNT = '1637872839' APP_NAME = 'devops-java-sample' SONAR_CREDENTIAL_ID = 'sonar-qube' }
stages { stage ('checkout scm') { steps { checkout(scm) } }
stage ('unit test') { steps { container ('maven') { sh 'mvn clean -gs `pwd`/configuration/settings.xml test' } } } stage ('build & push') { steps { container ('maven') { sh 'mvn -Dmaven.test.skip=true -gs `pwd`/configuration/settings.xml clean package' sh 'docker build -f Dockerfile-online -t $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER .' withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$DOCKER_CREDENTIAL_ID" ,)]) { sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin' sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER' } } } }
stage('push latest'){ 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('deploy to dev') { when{ branch 'master' } steps { input(id: 'deploy-to-dev', message: 'deploy to dev?') kubernetesDeploy(configs: 'deploy/dev-ol/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID") } } stage('push with tag'){ when{ expression{ return params.TAG_NAME =~ /v.*/ } } steps { container ('maven') { input(id: 'release-image-with-tag', message: 'release image with tag?') withCredentials([usernamePassword(credentialsId: "$GITHUB_CREDENTIAL_ID", passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) { sh 'git config --global user.email "kubesphere@yunify.com" ' sh 'git config --global user.name "kubesphere" ' sh 'git tag -a $TAG_NAME -m "$TAG_NAME" ' sh 'git push http://$GIT_USERNAME:$GIT_PASSWORD@github.com/$GITHUB_ACCOUNT/devops-java-sample.git --tags --ipv4' } sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME ' sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME ' } } } stage('deploy to production') { when{ expression{ return params.TAG_NAME =~ /v.*/ } } steps { input(id: 'deploy-to-production', message: 'deploy to production?') kubernetesDeploy(configs: 'deploy/prod-ol/**', enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID") } } } }
|
4、阿里云镜像仓库
1 2 3 4
| + 创建镜像仓库 + 登录仓库 + 拉取镜像 + 推送镜像
|
DevOps部署流水线
1、拉取gitee代码&参数化构建&环境变量
2、Sonar代码质量分析
- 配置阿里云镜像
- 进入sonar查看分析报告
- bug修改等
3、构建&推送镜像
- 配置阿里云私有镜像仓库
- 根据dockerfile 打包镜像
- 推送镜像
4、部署到k8s生产环境
5、发布
全链路最终部署
1、数据服务集群
2、微服务集群
3、gateway网关集群
4、nginx集群
5、vue后台
6、ingress controller网关路由
地址——>ingress controller——>动静分离nginx——>gateway——>微服务
1 2 3 4 5
| + 部署方式 + Jenkins流水线 + 自己打包部署k8s服务 + 拉取镜像自己运行 ...
|
集群监控
动态扩容节点
预警信息
监控信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| + k8s概念 + pod、server + nodeport等 + 应用路由 + ingress controller + 配置中心 + configMap + Devops + 自动化流水线 + 修改推送代码 + 运行流水线构建 + 监控资源 + 集群技术 + 主从、分片、选领导 + 各种集群 + Jenkins file + Docker file
|