1. DevOps。

DevOps是一种软件开发实践思想,强调开发(Dev)、测试(QA)及运维(Ops)之间的沟通合作,通过自动化流程,使得软件构建、测试、发布更快捷、频繁和可靠。

DevOps最佳实践技术手段-CI/CD。

产品设计->开发人员开发代码->测试人员测试功能->运维人员发布上线

CI:持续集成(Continuons integration,简称CI) 

持续集成是一种开发实践,它倡导团队成员需要更频繁的集成他们的工作,每次集成都通过自动化构建(包括编异、构建、自动化测试)来验证,从而尽快的发现集成中的错误。让正在开发的软件始终处于可工作状态,让产品可以尽快的迭代,同时还能保证高质量。 

CD:持续交付(Continuous Delivery) 

持续交付是持续集成的延伸也可以看成是持续集成的下一步,它将集成后的代码部署到类生产环境,确保可以以持续的方式快速向客户发送新的更改。如果代码

没有问题,可以继续部署到生产环境中。它强调的是,不管怎么更新,软件是随时随地可以交付的。 

CD:持续部署(Continuous Deployment) 

持续部署是持续交付的下一步,在持续交付的基础上,由开发或运维定期向生产环境部署稳定的构建版本,持续部署的目标是代码在任何时刻都是可部署的,并自动进入到生产环境。

敏捷VS DevOps 

1、 敏捷:及时响应需求变化,快速迭代 

2、 DevOps,基于敏捷基础演变而来,补齐持续交付流程短板,强调开发、测试、运维一体化,持续集成/持续交付流水线。

CI/CD流水线

 

 

 2. docker 部署gitlab

Gitlab:代码管理仓库。

可以直接使用公司gitlab,目前gitlab主打的是devOps platform,不仅可以管理代码,还可以做项目部署、项目集成。

复制代码
sudo docker run --detach \
  --hostname gitlab.xx.xx \
  --publish 443:443 --publish 80:80 --publish 222:22 \
  --name gitlab \
  --restart always \
  --volume /srv/gitlab/config:/etc/gitlab \
  --volume /srv/gitlab/logs:/var/log/gitlab \
  --volume /srv/gitlab/data:/var/opt/gitlab \
  gitlab/gitlab-ce:latest 
复制代码

hostname  域名 或 ip

publish 端口映射

restart 重启方式

gitlab/gitlab-ce:latest  镜像名称

volume 目录挂载 

3. 在gitlab上,搭建CI/CD环境。

CI/CD简单理解:就是当你把本地代码提交到gitlab上时,会自动触发流程,会执行一系列任务(pipeline流水线)。

CI/CD:持续集成,持续部署。是一个理念。提交代码以后,自动集成,自动部署,执行任务。

pipeline: 流水线,每一次提交代码后,都会触发流水线,流水线中,是由Stage组成,

Stage阶段(install, build, release, deploy),同一组的任务放到一个阶段。每个阶段,会有一个或多个任务(job)。

Job:任务(job_install,job_build, job_release, job_deploy, job_deploy2)。一条流水线,包含多个阶段,一个阶段包含多个任务。 任务是流水线里面最小的执行单元。

gitlab runner:所有任务,都是在gitlab runner中跑的。 它是一个CI/CD的执行环境,所有做的CI/CD操作,都是gitlab runner执行的。给CI/CD,pipeline提供运行环境。 是在启动的容器中注册的。

.gitlab-ci.yml:放在项目根目录下,定义流水线的内容,定义阶段,任务,以及流水线执行的脚本,使用哪个runner,使用哪些存储方式,使用哪些步骤,使用缩紧方式编写。

安装gitlab runner:

sudo docker run -d --name xxx --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest 

注册gitlab runner,让gitlab runner和gitlab产生联系:

复制代码
docker run --rm -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register \
  --non-interactive \
  --executor "docker" \
  --docker-image alpine:latest \
  --url "http://gitlab.xxx/" \
  --registration-token "xxx" \
  --description "first-register-runner" \
  --tag-list "test-cicd1,dockercicd1" \
  --run-untagged="true" \
  --locked="false" \
  --access-level="not_protected" 
复制代码

url: gitlab的地址

registration-token:注册token,在gitlab--Runners页面中找到。

tag-list:注册gitlab runner 的标签,指定流水线在哪个runner下跑,tag就是要运行的runner。 

gitlab runner属性: shared(共享), group, speeific(指定项目),locked,paused,

4..gitlab-ci.yml文件编写

任务的28个关键词分别是,
script, after_script, allow_failure, artifacts, before_script, cache, coverage, dependencies, environment, except, extends, image, include, interruptible, only, pages, parallel, release, resource_group, retry, rules, services, stage, tags, timeout, trigger, variables, when

全局的关键词
image,services,before_script,after_script,tags,cache,artifacts,retry,timeout,interruptible

最常任务中最常用的是这七个script,artifacts,stage, when,tags,image,cache,知道了这个七个关键词,一般的流水线就可以实现了。

写一个最简单的例子:

复制代码
image: node:alpine
stages:
- Install - Build - Release - Deploy
cache:
  key: vitepro
paths:
- node_modules job_install: stage:Install
  tags:
- xxx script:
- npm install job_build: stage:Build
tags:
- xxx script:
- npm run build
only:
- release job_release: stage:Release
tags:
- xxx script:
- echo 'my release job' job_deploy: stage:Deploy
image: docker
tags:
- xxx script:
- docker build -t viteimages .
- if [ $(docker ps -aq --filter name=myrochepc-container)]; then docker rm -rf myrochepc-container;fi
  - docker run -d -p 8080:80 --name myrochepc-container rochepcimages job_deploy2: stage:Deploy
 tags:
- xxx script:
- echo 'my deploy2 job'
when: manual
复制代码

 

stages:全局自定义阶段

stage:任务内的阶段, 必须从全局中选。用于归档一部分的job,按照定义的stage顺序来执行。 默认的stage有build,test,deploy, 此外还有两个特殊的.pre 和 .post。(注意:job执行的顺序不是按照编写的顺序,是按照stage定义的顺序来执行的。)

script:任务要执行的shell脚本内容,内容会被runner执行,在这里,你不需要使用git clone ....克隆当前的项目,来进行操作,因为在流水线中,每一个的job的执行都会将项目下载,恢复缓存这些流程,不需要你再使用脚本恢复。你只需要在这里写你的项目安装,编译执行,script可以是单行或者多行。(注意:script是一个job的必填内容,不可或缺。一个job最少有二个属性,一个是job name, 任务名称, 一个就是script。)

retry:重试,当任务失败时,自动重试。

when:可以指定失败原因(即:什么失败时,可以重试)。实现在发生故障或尽管发生故障时仍能运行的作业。比如你要在任务失败后需要触发一个job,或者你需要手动执行任务,或者当你一个任务执行成功后,执行另一个任务.

on_success 所有任务执行成功后
on_failure 当至少一个任务失败后
always 执行作业,而不考虑作业在早期阶段的状态。
manual 手动执行任务
delayed 延迟执行任务
never
在rules中不排除执行的任务
在workflow:rules不允许的流水线

image:指定一个基础Docker镜像作为基础运行环境,经常用到的镜像有node nginx docker。image的作用就是给当前任务或者当前流水线设置一个基础环境,有可能是nodejs,也有可能是java, go, php,可以设置当前流水线的,也可以设置当前任务的。

tags:用于指定Runner,tags的取值范围是在该项目可见的runner tags中,可以在Setting =>CI/CD => Runner 中查看的到。
要知道,改属性可以设置全局,不设置则默认使用公有Runner去执行流水线。每个任务可以指定一个Runner,可以指定多个标签,但runner却只能一个。以一个为准。tags是在我们注册Runner是配置的,后续也可以更改。

only/except : 是规定当前job的可见状态,一个项目有很多分支,tag,我们的流水线,为了对特定的分支,特定的tag执行不同的job,这里就要使用only和except
在任务上加上这一段代码,就表明当前任务只有在master分支可以运行

也可以根据当前的代码变动是合并,还是推送,还是使用API来触发的。
如果一个任务没有only属性,那默认就是
only: ['branches', 'tags'] 操作分支或者tags都会触发流水线。

cache: 缓存, 是将当前工作环境目录中的一些文件,一些文件夹存储起来,用于在各个任务初始化的时候恢复。避免多个下载同样的包,能够大大优化流水线效率。在前端项目中,我们经常把node_modules缓存起来,这样一条流水线都可以使用这些下载好的包。在java项目中经常把maven下载的包缓存起来。以备后用。缓存可以设置流水线全局,也可以在job中设置。
cache有以下的参数:

paths -- 当前工作环境下的目录
key -- 存储的key,key不变不会重新生成缓存,
prefix -- 使用一些文件制作成文件hash值,当做key的一部分,
untracked -- 是否缓存git忽略的文件
when -- 定义何时存储缓存 on_success;on_failure;always
policy -- 缓存是否要在job完成后重新上传

before_script:是用于在每个任务之前执行的脚本,但是会在artifacts恢复之后执行。你可以这样定义一个全局的before_script,也可以在一个任务中中单独定义。任务中的before_script会覆盖全局的before_script。

after_script: 用于定义多行脚本,会在任务执行完成后执行,即使任务失败也会被执行。如果任务被取消或者超时,after_script就不会被执行了,目前官方正在计划这个特性。可以定义全局的,也可以定义局部的 
dependencies: 是定义特定的job运行规则。默认artifacts是从当前阶段产生,在后续的阶段都会被下载,但我们可以使用dependencies关键词来控制artifacts从哪里下载

environment:是用于定义环境变量,可以是用k-v的方式定义,需要注意的是这里定义的环境变量是不能在script值使用的。这个关键词可以和review和merge搭配。

extends: 可以使一个任务继承另一个任务。在流水线中,以 . 开头的任务名,都是隐藏的任务。不会被执行。 被Dist继承后,相同的key会以Dist为准,Dist没有的,而.dist有的,则合并到Dist中.

include: 使用include可以导入一个或多个额外的yaml文件到你的CICD配置里,这样你就可以将一个很长的流水线,分隔出来。使用include来引入。

也可以将几个流水线中相同的配置,提取出来,公用。引入的文件扩展名 必须是.yaml或者.yml两种,其他的不行。
include 关键词下,有四个可选性:
local, 引入一个当前项目的文件
file, 引入一个不同项目的文件
remote, 引入一个公网文件
template, 引入一个由GitLab提供的模板

复制代码
include:
  - project: 'devops/cicd-template/ci-template'
    ref: master
    file: 'fr-nodejs-entry.yml'

variables:
  CI_PROJECT_NAME: "xx"
  NODEPORT: 31583
  NODELABEL: "xxx"
  TEAM: "xxx"
  LIMITS_CPU: "1000m"
  LIMITS_MEM: "2000Mi"
  REQUEST_CPU: "500m"
  REQUEST_MEM: "1000Mi"
  KUBE_NAMESPACE: "default"
  REPILICA: 1

Dist:
  extends: .dist
  stage: Build
  tags:
    - "common-runner-frontend"

Sonar-Scanner:
  extends: .code_scan
  stage: Build
  tags:
    - "common-runner-frontend"
Build_docker_image:
  stage: Package
  extends: .build_image
  dependencies:
    - Dist
  tags:
    - "common-runner-frontend"
  only:
    refs:
      - develop
  variables:
    EKS: "eks"
    KUBE_ENV: "dev"
    KUBE_NAMESPACE: "xxx"
    REPILICA: 1
  extends: .deploytok8s
  tags:
    - shell
Deploy_staging:
  only:
    refs:
      - staging
  variables:
    KUBE_ENV: "staging"
    KUBE_PROPS_ENCRYPTION_KEY: "secret-stage-git"
    REPILICA: 1
  extends: .deploytok8s
  tags:
    - shell
Deploy_preprod:
  only:
    refs:
      - release
  variables:
    INGRESS_HOST: "$CI_PROJECT_NAME-preprod"
    KUBE_ENV: "staging"
    KUBE_PROPS_ENCRYPTION_KEY: "secret-preprod-git"
    NODEPORT: 31584
    REPILICA: 2
    KUBE_NAMESPACE: 'preproduction'
  extends: .deploytok8s
  tags:
    - shell
Deploy_uat:
  only:
    refs:
      - uat
  variables:
    INGRESS_HOST: "$CI_PROJECT_NAME-uat"
    KUBE_ENV: "staging"
    KUBE_PROPS_ENCRYPTION_KEY: "secret-uat-git"
    NODEPORT: 31585
    REPILICA: 1
    KUBE_NAMESPACE: 'uat'
  extends: .deploytok8s
  tags:
    - shell
deploy_prod:
  rules:
    - if: '$CI_COMMIT_REF_NAME == "master"'
      when: manual
  variables:
    REGISTRY: "$AWS_ECR_REPO_PROD"
    KUBE_ENV: "master"
    KUBE_PROPS_ENCRYPTION_KEY: "secret-prod-git"
    NODEPORT: 31583
    REPILICA: 3
    KUBE_NAMESPACE: 'default'
  extends: .deploytok8s
  tags:
    - shell
复制代码
fr-nodejs-entry.yml
复制代码
stages:
  - Notice
  - Build
  - Package
  - Deployment

variables:
  AWS_PROD: 'xxx'
  AWS_NOPROD: 'xxx'
  AWS_ECR: 'xxx.com.cn'
  NODEJS_IMAGE_TAG: 'master-52'
  SONAR_IMAGE_TAG: 'master'
  PROJECT_ECR_NAME: ''
  PFS_IMAGE: 'xxx:$CI_COMMIT_REF_NAME-latest'
  KUBE_NAMESPACE: 'default'
  KUBE_ENV: 'dev'
  KUBE_PROPS_ENCRYPTION_KEY: 'secret-dev-git'
  NODEPORT: ''
  REPILICA: '1'
  NODELABEL: ''
  TEAM: ''
  LIMITS_CPU: '1000m'
  LIMITS_MEM: '2000Mi'
  REQUEST_CPU: '100m'
  REQUEST_MEM: '500Mi'
  EKS: 'xxx'
  NPM_ACCOUNT: '$NPM_ACCOUNT'
  NPM_PWD: '$NPM_PWD'
  NPM_EMAIL: '$NPM_EMAIL'
  NPM_REGISTRY: '$NPM_REGISTRY'

.dist:
  image: xxx
  stage: Build
  only:
    refs:
      - staging
      - develop
      - master
      - release
      - merge_requests
      - uat
  tags:
    - common-runner
  allow_failure: false
  cache:
    paths:
      - node_modules/
  artifacts:
    untracked: false
    expire_in: 20 mins
    when: on_success
    paths:
      - ./build
      - Dockerfile
  script:
- npm install -g npm-cli-login
- echo "building artifacts" - npm config set registry ${NPM_REGISTRY} - npm install - npm run build .code_scan: image: name: xxx stage: Build only: refs: - staging - develop tags: - common-runner script: - sonar-scanner .build_image: image: xxx stage: Package services: - name: xxx alias: docker entrypoint: ['env', '-u', 'DOCKER_HOST'] command: ['dockerd-entrypoint.sh'] only: refs: - develop - staging - release - master - uat dependencies: - dist variables: # GIT_STRATEGY: none DOCKER_HOST: tcp://docker:xxx/ DOCKER_DRIVER: xxx DOCKER_TLS_CERTDIR: '' script: - docker run -itd $REGISTRY/$PFS_IMAGE /bin/sh - mkdir -p ./xxx - docker cp `docker ps | grep frontend |awk '{print $1}'`:/usr/src/app ./xxx - echo "build docker image start" - docker build -t ${IMAGE_NAME} . - docker push ${IMAGE_NAME} - echo "build docker image finished" tags: - common-runner .deploytok8s: stage: Deployment script: - echo $KUBE_ENV - echo $KUBE_PROPS_ENCRYPTION_KEY - echo $CI_COMMIT_REF_SLUG tags: - shell
复制代码

 原文链接:https://blog.csdn.net/github_35631540/article/details/111029163