时间 标题 内容




上午




Kubectl

1. 根据应用编写Deployments部署文件
2. Jenkins流水线中使用Sed替换文件信息
3. Jenkins 集成Kubectl工具完成应用发布



下午


Helm(GitOps)

1. Helm部署工具的基本概念
2. 编写Helm Charts模板
3. 使用Helm将应用部署到K8s
4. 将Charts托管到GitLab 实践GitOps

【本次课程总结】
本次课程主要讲解基于Kubernetes的应用发布流水线的实现:

  • 了解Docker的基础知识,完成CI流水线中的docker镜像上传步骤。
  • 学习Kubernetes的基础知识, 手动编写Deployment模板,完成应用的发布。
  • 将部署文件存储在Git仓库, 复用上次课程的”生成版本文件”步骤,来完成对该部署文件的版本更新。
  • 学习k8s的发布策略,实践完成基于service的蓝绿部署和基于ingress的灰度发布(手动)。
  • 使用kubectl完成对应用的发布, 调试并生成CD流水线。
  • 学习Helm基础知识, 手动编写helm chart完成打包和发布更新回滚。
  • 调试完成基于Helm的CI/CD GitOps流水线。

课程直播与回看

注意: 上午在创建jenkins slave 的时候遇到了坑点,花费了40多分钟排错,还好最后学习到了新的方式方法解决了此类存在已久的bug。 下午在编写sed 和awk 命令时花费了很多时间, sed 中默认使用 ‘/‘分割在jenkins中要换一下,换成”#”没问题测试通过。 awk 中的位置参数 “$” 要用反斜杠转义”‘{ print \$1}’”。


实验与素材:


1. 基于Kubectl的GitOps CI/CD

1.1 CI流水线设计与实现

此次项目我们使用了jenkins共享库来完成最佳实践。 jenkinsfile第一行就是要导入我们的共享库。@Library("devopslib@master") _

我们在共享库中编写了一些特定的处理类:

  • src/org/devops/mytools.groovy 存放小工具(代码下载, 邮件通知)
  • src/org/devops/builds.groovy 构建类工具
  • src/org/devops/sonarqube.groovy 代码扫描工具
  • src/org/devops/artifacts.groovy 制品管理工具
  • src/org/devops/gitlab.groovy 版本控制系统接口操作工具

在Jenkinsfile中导入这些类

  1. def mytools = new org.devops.mytools()
  2. def builds = new org.devops.builds()
  3. def sonar = new org.devops.sonarqube()
  4. def artifacts = new org.devops.artifacts()
  5. def gitlab = new org.devops.gitlab()

有些参数需要用户在Jenkins页面构建前填写的:

  • 用户需要在jenkins作业中配置好要构建的代码仓库的地址。(一般不需要改, 可以使用选项参数)
  • 每次构建需要输入此代码库要构建的代码分支。 (字符串参数)
  • 选择本次构建要使用的构建工具(选项参数maven、ant、gradle、npm)
  • 用户自行选择是否跳过代码扫描(选项参数 true、false)

image.png

  1. //UI上面的参数
  2. String branchName = "${env.branchName}" // 分支名称
  3. String gitHttpURL = "${env.gitHttpURL}" // 仓库地址
  4. String buildType = "${env.buildType}" // 构建类型
  5. String skipSonar = "${env.skipSonar}" // 是否跳过扫描

为了适配不同的构建工具,专门维护了一个map用于管理不同的构建工具的path。标准化 标准化 标准化, 也就是后期所有的agent节点都要安装这些工具的时候,要使用约定好的目录位置。

  1. def buildTools = [ "maven" : "/usr/local/apache-maven-3.8.1",
  2. "gradle": "/usr/local/gradle-6.8.3/",
  3. "golang": "/usr/local/go",
  4. "npm" : "/usr/local/node-v14.16.1-linux-x64/",
  5. "sonar" : "/usr/local/sonar-scanner-4.6.0.2311-linux/"]

我们在流水线中定义一些全局变量:

  • 通过作业的名称拿到我们的制品库名称(anyops)
  • 通过作业名称拿到业务简称(anyops)
  • 通过作业名称拿到应用名称(anyops-devops-service/ anyops-devops-ui)
  • 通过分支名称拿到对应的版本号(release-1.1.1 对应 1.1.1 )
    1. // 业务名称、应用名称、版本
    2. String repoName = "${JOB_NAME.split('/')[0]}"
    3. String buName = "${JOB_NAME.split('/')[0]}"
    4. String appName = "${JOB_NAME.split('/')[1].split("_")[0]}"
    5. String releaseVersion = "${branchName.split('-')[1]}"

流水线运行信息

此条流水线运行在标签为”build”的节点上, 跳过默认的checkout步骤。

  1. agent { label "build" }
  2. options {
  3. skipDefaultCheckout true
  4. }

阶段与节点

image.png

下载代码

  1. stage("GetCode"){
  2. steps{
  3. script{
  4. mytools.GetCode("git",branchName,gitHttpURL)
  5. }
  6. }
  7. }

构建代码

  1. stage("Build"){
  2. steps {
  3. script {
  4. builds.Build(buildTools, buildType)
  5. }
  6. }
  7. }

代码扫描

  1. stage("SonarScan"){
  2. when {
  3. environment name: 'skipSonar', value: 'false'
  4. }
  5. steps{
  6. script{
  7. projectName = "${appName}"
  8. sonar.SonarScan(projectName, buildType, buildTools)
  9. }
  10. }
  11. }

构建上传镜像

  • 需要将docker镜像仓库的用户认证信息,以用户名和密码类型的凭据在Jenkins中存储;
  • docker仓库:registry.cn-beijing.aliyuncs.com/${buName}/${appName};
  • 镜像标签: ${releaseVersion}-${nowDate} 即 版本号-日期;
  • 步骤: 登录镜像仓库> 构建镜像 > 上传镜像 > 删除本地镜像(节省空间);

image.png

  1. stage("PushImage"){
  2. steps{
  3. script{
  4. withCredentials([usernamePassword(credentialsId: '6ed6e3ef-fdca-493f-a8a4-613f70aca281', passwordVariable: 'password', usernameVariable: 'username')]) {
  5. env.nowDate = sh returnStdout: true, script: 'date +%Y%m%d%H%M%S'
  6. env.nowDate = env.nowDate - "\n"
  7. env.releaseVersion = "${env.branchName}"
  8. env.imageTag = "${releaseVersion}-${nowDate}"
  9. env.dockerImage = "registry.cn-beijing.aliyuncs.com/${buName}/${appName}:${env.imageTag}"
  10. sh """
  11. docker login -u ${username} -p ${password} registry.cn-beijing.aliyuncs.com
  12. docker build -t ${dockerImage} -f ./Dockerfile .
  13. sleep 1
  14. docker push ${dockerImage}
  15. sleep 1
  16. docker rmi ${dockerImage}
  17. """
  18. }
  19. }
  20. }
  21. }

更新生成版本文件

  • 步骤: 拿到 env仓库中的default.yaml模板文件, 然后替换内容,更新到版本库。
  • 更新对象:

    • APPNAME(应用名称)对应Jenkins作业名称;
    • VERSION (发布版本) 对应版本分支中的版本号;
    • NAMESPACE (名称空间) 对应业务名称;
    • INAGENAME(镜像名称) ```groovy stage(“ReleaseFile”){

      1. steps {
      2. script {
      3. //下载版本库文件 anyops-devops-service/release.yaml
      4. response = gitlab.GetRepoFile(13,"default.yaml", "master")
      5. sh "rm -fr default.yaml"
      6. writeFile file: 'default.yaml', text: """${response}"""
      7. sh """
      8. ## 替换APPNAME
      9. sed -i 's#__APPNAME__#${appName}#g' default.yaml
      10. sed -i 's#__VERSION__#${env.releaseVersion}#g' default.yaml
      11. sed -i 's#__NAMESPACE__#${buName}#g' default.yaml
      12. sed -i 's#__IMAGENAME__#${env.dockerImage}#g' default.yaml
      13. """
      14. newYaml = sh returnStdout: true, script: 'cat default.yaml'
      15. println(newYaml)
      16. //更新gitlab文件内容
      17. base64Content = newYaml.bytes.encodeBase64().toString()
      18. // 会有并行问题,同时更新报错
      19. try {
      20. gitlab.UpdateRepoFile(13,"${appName}%2f${branchName}.yaml",base64Content, "master")
      21. } catch(e){
      22. gitlab.CreateRepoFile(13,"${appName}%2f${branchName}.yaml",base64Content, "master")
      23. }
      24. }
      25. }

      }

  1. <a name="G7A4i"></a>
  2. ###
  3. 镜像仓库截图:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2584012/1620564080420-859ef974-54fc-44c1-a743-a6846febc088.png#clientId=u313b3434-a091-4&from=paste&height=509&id=u9230562f&originHeight=1018&originWidth=1933&originalType=binary&size=215034&status=done&style=none&taskId=u04a3e9b1-02f0-4695-b669-9078de903bb&width=966.5)
  4. ---
  5. <a name="VBHhT"></a>
  6. ## 1.2 CD流水线设计与实现
  7. 此次项目我们使用了jenkins共享库来完成最佳实践。 `jenkinsfile`第一行就是要导入我们的共享库。`@Library("devopslib@master") _`
  8. 我们在共享库中编写了一些特定的处理类:
  9. - src/org/devops/mytools.groovy 存放小工具(代码下载, 邮件通知)
  10. - src/org/devops/gitlab.groovy 版本控制系统接口操作工具
  11. 在Jenkinsfile中导入这些类
  12. ```bash
  13. def mytools = new org.devops.mytools()
  14. def gitlab = new org.devops.gitlab()

只有一个参数需要用户在Jenkins页面构建前填写的:

  • 用户在页面输入发布版本: releaseVersion, 例如 1.1.1

image.png

  1. //UI上面的参数
  2. String releaseVersion = "${env.releaseVersion}" // 发布版本

我们在流水线中定义一些全局变量:

  • 通过作业名称拿到业务简称(anyops)
  • 通过作业名称拿到应用名称(anyops-devops-service/ anyops-devops-ui)
    1. // 业务名称、应用名称
    2. String buName = "${JOB_NAME.split('/')[0]}"
    3. String appName = "${JOB_NAME.split('/')[1].split("_")[0]}"

流水线运行信息

此条流水线运行在标签为”k8snode”的节点上, 跳过默认的checkout步骤。(课程中是在k8s的master节点启动了一个jnlp的Jenkins Slave)

  1. agent { label "k8snode"}
  2. options {
  3. skipDefaultCheckout true
  4. }

阶段与节点

image.png

获取发布文件

  • 下载CI流水线生成的版本文件到本地; ```groovy stage(“GetEnvFile”){

    1. steps{
    2. script{
    3. //下载版本库文件 anyops-devopsdocker-ui/release-1.1.9.yaml
    4. response = gitlab.GetRepoFile(13,"${appName}%2frelease-${releaseVersion}.yaml", "master")
    5. sh "rm -fr release-${releaseVersion}.yaml"
    6. writeFile file: "release-${releaseVersion}.yaml", text: """${response}"""
    7. }
    8. }
    9. }
  1. <a name="oQgp3"></a>
  2. ###
  3. 应用发布
  4. - 创建名称空间,更新应用,查看REVISION历史。
  5. ```groovy
  6. stage("Deploy"){
  7. steps {
  8. script {
  9. sh """
  10. kubectl create ns ${buName} || echo true
  11. kubectl apply -f ./release-${releaseVersion}.yaml
  12. kubectl rollout history deployment/${appName} -n ${buName}
  13. """
  14. }
  15. }
  16. }

回滚步骤(交互)

  • 给用户提供两个选项 :rollback执行回滚,skip跳过;
  • 使用kubectl rollout undo 默认回滚上个版本; ```groovy stage(‘RollBack’) {

    1. input {
    2. message "RollBack ? "
    3. ok "Submit"
    4. submitter "zeyang,aa"
    5. parameters {
    6. choice(choices: ["rollback", "skip"], description: '', name: 'actions')
    7. }
    8. }
    9. steps {
    10. script {
    11. echo "Actions is ${actions}, doing......."
    12. if ( "${actions}" == "rollback"){
    13. sh """ kubectl rollout undo deployment/${appName} -n ${buName} """
    14. } else {
    15. println("Skip rollback .....")
    16. }
    17. }
    18. }
    19. }
  1. ---
  2. <a name="FSayr"></a>
  3. # 2. 基于Helm的GitOps CI/CD
  4. <a name="N1H1v"></a>
  5. ## 2.1 CI流水线设计与实现
  6. 此部分可以参考上面“基于kubectl发布”阶段, 相同的阶段代码。
  7. <a name="S2KXB"></a>
  8. ### 阶段与节点
  9. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/2584012/1620565418202-2b90ac90-a34e-4199-81b3-efcfc3758928.png#clientId=u313b3434-a091-4&from=paste&height=124&id=uc012d19c&originHeight=192&originWidth=1155&originalType=binary&size=17401&status=done&style=none&taskId=uc1e184b4-df6e-443a-97f5-d7bf8f6d27e&width=743.5)<br />此部分可以参考上面“基于kubectl发布”阶段, 相同的阶段代码。
  10. 更新生成版本文件
  11. 此处的版本文件不再是一个文件了, 而是一个chart包。如何生成:
  12. ```groovy
  13. helm create "${appName}"
  14. cd "${appName}"
  15. git push 到版本库
  • 步骤: 拿到 helm chart仓库中的values.yaml模板文件, 然后替换镜像,更新到版本库。
  • 更新对象:

    • image.repository (镜像仓库名称)
    • image.tag (镜像标签) ```groovy stage(“ReleaseFile”){

      1. steps {
      2. script {
      3. //下载版本库文件 anyops-devopshelm-ui/values.yaml
      4. response = gitlab.GetRepoFile(14,"${appName}%2fvalues.yaml", "master")
      5. yamlData = readYaml text: """${response}"""
      6. println(yamlData)
      7. yamlData.image.repository = "${env.repository}"
      8. yamlData.image.tag = "${env.imageTag}"
      9. sh "rm -fr default.yaml"
      10. writeYaml charset: 'UTF-8', data: yamlData, file: 'default.yaml'
      11. newYaml = sh returnStdout: true, script: 'cat default.yaml'
      12. println(newYaml)
      13. //更新gitlab文件内容
      14. base64Content = newYaml.bytes.encodeBase64().toString()
      15. // 会有并行问题,同时更新报错
      16. try {
      17. gitlab.UpdateRepoFile(14,"${appName}%2fvalues.yaml",base64Content, "master")
      18. } catch(e){
      19. gitlab.CreateRepoFile(14,"${appName}%2fvalues.yaml",base64Content, "master")
      20. }
      21. }
      22. }

      }

  1. ---
  2. <a name="JmGlw"></a>
  3. ## 2.2 CD流水线设计与实现
  4. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/2584012/1620566060144-5970bcd5-06d3-4574-aa34-f81d8f2688eb.png#clientId=u313b3434-a091-4&from=paste&height=300&id=u2541d993&originHeight=600&originWidth=1566&originalType=binary&size=102853&status=done&style=none&taskId=ubea2268e-0651-4bc4-9427-e6357de3bb8&width=783)
  5. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/2584012/1620565850507-e81eadbd-1d7a-48c5-8928-1fe743b6ca3a.png#clientId=u313b3434-a091-4&from=paste&height=475&id=u19741f0d&originHeight=950&originWidth=1523&originalType=binary&size=86062&status=done&style=none&taskId=u0f9e73d3-674c-470c-81e7-517b01064eb&width=761.5)
  6. 下载chart仓库
  7. ```groovy
  8. stage("GetEnvFile"){
  9. steps{
  10. script{
  11. mytools.GetCode("git",branchName,gitHttpURL)
  12. }
  13. }
  14. }

helm发布应用

  • 创建名称空间,打包,获取REVISION历史(便于回滚) ```groovy stage(“Deploy”){
    1. steps {
    2. script {
    3. sh """
    4. kubectl create ns ${buName} || echo true
    5. helm package "${appName}/"
    6. helm install "${appName}" ./"${appName}"-*.tgz -n ${buName} || helm upgrade "${appName}" ./"${appName}"-*.tgz -n ${buName}
    7. helm history "${appName}" -n ${buName}
    8. """
    9. env.revision = sh returnStdout: true, script: """helm history ${appName} -n ${buName} | grep -v 'REVISION' | awk '{print \$1}' """
    10. println("${env.revision}")
    11. println("${env.revision.split('\n').toString()}")
    12. env.REVISION = "${env.revision.split('\n').toString()}"
    13. println("${env.REVISION}")
    14. }
    15. }
    16. }
  1. 回滚步骤
  2. - 交互式用户选择REVISION 触发Helm rollback
  3. ```groovy
  4. stage('RollBack') {
  5. steps {
  6. script {
  7. def result = input message: 'RollBack?', ok: 'submit', parameters: [choice(choices: "${env.REVISION}", description: '', name: 'revision')]
  8. env.result = result - "\n"
  9. echo "Actions is ${env.result}, doing......."
  10. if ( "${env.result}" != ""){
  11. sh """ helm rollback ${appName} ${env.result} -n ${buName} """
  12. } else {
  13. println("Skip rollback .....")
  14. }
  15. }
  16. }
  17. }

3. 核心技术点讲解

3.1 Docker基础

Docker官网: https://www.docker.com/
Docker中文社区: http://www.docker.org.cn/
Docker HUB: https://hub.docker.com/

Docker 使用客户端-服务器 (C/S) 架构模式。Docker 客户端会与 Docker 守护进程进行通信。Docker 守护进程会处理复杂繁重的任务,例如建立、运行、发布Docker 容器。Docker 客户端和守护进程可以运行在同一个系统上,当然也可以使用 Docker 客户端去连接一个远程的 Docker 守护进程。Docker 客户端和守护进程之间通过 socket 或者 RESTful API 进行通信。

image.png

  • Docker守护进程: Docker 守护进程运行在一台主机上。用户并不直接和守护进程进行交互,而是通过Docker 客户端间接和其通信。

  • Docker客户端: 实际上是 docker 的二进制程序,是主要的用户与 Docker 交互方式。它接收用户指令并且与背后的 Docker 守护进程通信,

  • Docker 镜像: Docker 容器运行时的只读模板,每一个镜像由一系列的层 (layers) 组成
  • Docker 仓库: 仓库用来保存镜像,可以理解为代码控制中的代码仓库。同样的,Docker 仓库也有公有和私有的概念。
  • Docker 容器: 一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。

特性

  • 灵活:复杂的应用程序也可以容器化。
  • 轻量级:容器利用并共享了主机内核,在系统资源方面比虚拟机更加有效。
  • 可移植性:可以在本地构建,部署到云并在任何地方运行。
  • 松散耦合:容器是高度自给自足并封装的容器,使在不破坏其他容器的情况下更换或升级。
  • 可扩展:在数据中心内增加并自动分布容器副本。
  • 安全:容器将积极的约束和隔离应用于流程,而无需用户方面的任何配置。

Docker安装

yum源:https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo

可以替换文件中的url,这样下载速度更快。

  1. :%s/download.docker.com/mirrors.tuna.tsinghua.edu.cn\/docker-ce/g

Docker version 19.03.12, build 48a66213fe

  1. dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
  2. dnf list docker-ce
  3. dnf install docker-ce --nobest -y
  4. systemctl start docker
  5. systemctl enable docker
  6. docker -v

Docker指令

  1. [root@myserver ~]# docker -h
  2. Flag shorthand -h has been deprecated, please use --help
  3. Usage: docker [OPTIONS] COMMAND
  4. A self-sufficient runtime for containers
  5. Options:
  6. --config string Location of client config files (default "/root/.docker")
  7. -c, --context string Name of the context to use to connect to the daemon (overrides
  8. DOCKER_HOST env var and default context set with "docker context
  9. use")
  10. -D, --debug Enable debug mode
  11. -H, --host list Daemon socket(s) to connect to
  12. -l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal")
  13. (default "info")
  14. --tls Use TLS; implied by --tlsverify
  15. --tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
  16. --tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
  17. --tlskey string Path to TLS key file (default "/root/.docker/key.pem")
  18. --tlsverify Use TLS and verify the remote
  19. -v, --version Print version information and quit
  20. Management Commands:
  21. builder Manage builds
  22. config Manage Docker configs
  23. container Manage containers
  24. context Manage contexts
  25. engine Manage the docker engine
  26. image Manage images
  27. network Manage networks
  28. node Manage Swarm nodes
  29. plugin Manage plugins
  30. secret Manage Docker secrets
  31. service Manage services
  32. stack Manage Docker stacks
  33. swarm Manage Swarm
  34. system Manage Docker
  35. trust Manage trust on Docker images
  36. volume Manage volumes
  37. Commands:
  38. attach Attach local standard input, output, and error streams to a running container
  39. build Build an image from a Dockerfile
  40. commit Create a new image from a container's changes
  41. create Create a new container
  42. import Import the contents from a tarball to create a filesystem image
  43. load Load an image from a tar archive or STDIN
  44. login Log in to a Docker registry
  45. logout Log out from a Docker registry
  46. push Push an image or a repository to a registry
  47. rmi Remove one or more images
  48. save Save one or more images to a tar archive (streamed to STDOUT by default)
  49. tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  50. update Update configuration of one or more containers

info 系统信息

  1. [root@myserver ~]# docker info
  2. Client:
  3. Debug Mode: false
  4. Server:
  5. Containers: 0
  6. Running: 0
  7. Paused: 0
  8. Stopped: 0
  9. Images: 0
  10. Server Version: 18.09.1
  11. Storage Driver: overlay2
  12. Backing Filesystem: xfs
  13. Supports d_type: true
  14. Native Overlay Diff: true
  15. Logging Driver: json-file
  16. Cgroup Driver: cgroupfs

version 版本信息

  1. [root@myserver ~]# docker version
  2. Client: Docker Engine - Community
  3. Version: 19.03.12
  4. API version: 1.39
  5. Go version: go1.13.10
  6. Git commit: 48a66213fe
  7. Built: Mon Jun 22 15:46:54 2020
  8. OS/Arch: linux/amd64
  9. Experimental: false
  10. Server: Docker Engine - Community
  11. Engine:
  12. Version: 18.09.1
  13. API version: 1.39 (minimum version 1.12)
  14. Go version: go1.10.6
  15. Git commit: 4c52b90
  16. Built: Wed Jan 9 19:06:30 2019
  17. OS/Arch: linux/amd64
  18. Experimental: false
  19. wait Block until one or more containers stop, then print their exit codes

search 查找镜像

  1. docker search hello-world

pull 下载镜像(docker hub)

  1. [root@myserver ~]# docker pull hello-world
  2. Using default tag: latest
  3. latest: Pulling from library/hello-world
  4. 0e03bdcc26d7: Pull complete
  5. Digest: sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9
  6. Status: Downloaded newer image for hello-world:latest
  7. docker.io/library/hello-world:latest

images 查看本地的镜像

  1. [root@myserver ~]# docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. hello-world latest bf756fb1ae65 6 months ago 13.3kB

run 运行容器

  • -i : 交互模式
  • -t: 分配一个终端
  • -d: 后台运行
  • —name: 指定容器的名称
  • -p: 端口绑定
  1. docker run [options] IMAGE
  2. docker run hello-world
  3. docker run --name mywebserver -it nginx
  4. [root@myserver ~]# docker run --name mywebserver -itd nginx
  5. 8d485b358cc693c1e2b2d9b5c1d1a8092265d79bdcf1ee54d3d2f615f4f22064
  6. [root@myserver ~]# docker ps
  7. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  8. 8d485b358cc6 nginx "/docker-entrypoint.…" 6 seconds ago Up 5 seconds 80/tcp mywebserver

ps 查看容器进程( -a 所有的,正在运行、已经停止的)

  1. [root@myserver ~]# docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. [root@myserver ~]# docker ps -a
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 01bdedde3725 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago hopeful_mendel

rm 删除容器 (-f 强制)

  1. ## 指定容器的名称
  2. [root@myserver ~]# docker rm mywebserver
  3. mywebserver
  4. [root@myserver ~]# docker ps -a
  5. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  6. 01bdedde3725 hello-world "/hello" 9 minutes ago Exited (0) 9 minutes ago hopeful_mendel
  7. ## 指定容器的ID删除
  8. [root@myserver ~]# docker rm 01bdedde3725
  9. 01bdedde3725
  10. [root@myserver ~]# docker ps -a
  11. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  12. [root@myserver ~]#

start/restart/stop/ 容器控制

  1. [root@myserver ~]# docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. 8d485b358cc6 nginx "/docker-entrypoint.…" 20 minutes ago Up 20 minutes 80/tcp mywebserver
  4. [root@myserver ~]# docker stop mywebserver
  5. mywebserver
  6. [root@myserver ~]# docker ps
  7. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  8. [root@myserver ~]# docker start mywebserver
  9. mywebserver
  10. [root@myserver ~]# docker ps
  11. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  12. 8d485b358cc6 nginx "/docker-entrypoint.…" 21 minutes ago Up 3 seconds 80/tcp mywebserver
  13. [root@myserver ~]# docker restart mywebserver
  14. mywebserver

stats 显示容器使用的资源(CPU)

  1. docker stats mywebserver
  2. [root@myserver ~]# docker stats mywebserver
  3. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
  4. 8d485b358cc6 mywebserver 0.00% 2.309MiB / 3.664GiB 0.06% 3.44kB / 0B 0B / 0B 2
  5. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PID

logs 查看容器日志(-f 动态更新)

  1. [root@myserver ~]# docker logs -f mywebserver
  2. /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
  3. /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
  4. /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
  5. 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
  6. 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
  7. /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
  8. /docker-entrypoint.sh: Configuration complete; ready for start up
  9. /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
  10. /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
  11. /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
  12. 10-listen-on-ipv6-by-default.sh: IPv6 listen already enabled, exiting
  13. /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
  14. /docker-entrypoint.sh: Configuration complete; ready for start up
  15. /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
  16. /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
  17. /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
  18. 10-listen-on-ipv6-by-default.sh: IPv6 listen already enabled, exiting
  19. /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
  20. /docker-entrypoint.sh: Configuration complete; ready for start up

pause/unpause 暂停状态

  1. [root@myserver ~]# docker pause mywebserver
  2. mywebserver
  3. [root@myserver ~]# docker ps
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 8d485b358cc6 nginx "/docker-entrypoint.…" 27 minutes ago Up 5 minutes (Paused) 80/tcp mywebserver
  6. [root@myserver ~]# docker unpause mywebserver
  7. mywebserver
  8. [root@myserver ~]# docker ps
  9. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  10. 8d485b358cc6 nginx "/docker-entrypoint.…" 27 minutes ago Up 6 minutes 80/tcp mywebserver
  11. [root@myserver ~]#

rename 重命名

  1. docker rename CONTAINER NEW_NAME
  2. [root@myserver ~]# docker rename mywebserver webserver
  3. [root@myserver ~]# docker ps
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. 8d485b358cc6 nginx "/docker-entrypoint.…" 29 minutes ago Up 8 minutes 80/tcp webserver

inspect 显示容器的详细属性信息

  1. [root@myserver ~]# docker inspect webserver
  2. [
  3. {
  4. "Id": "8d485b358cc693c1e2b2d9b5c1d1a8092265d79bdcf1ee54d3d2f615f4f22064",
  5. "Created": "2020-07-09T01:55:08.20199984Z",
  6. "Path": "/docker-entrypoint.sh",
  7. "Args": [
  8. "nginx",
  9. "-g",
  10. "daemon off;"
  11. ],
  12. "State": {
  13. "Status": "running",
  14. "Running": true,
  15. "Paused": false,
  16. "Restarting": false,
  17. "OOMKilled": false,
  18. "Dead": false,
  19. "Pid": 6429,
  20. "ExitCode": 0,
  21. "Error": "",
  22. "StartedAt": "2020-07-09T02:16:41.996582526Z",
  23. "FinishedAt": "2020-07-09T02:16:40.968627884Z"
  24. },

kill 关闭容器进程

  1. [root@myserver ~]# docker kill webserver
  2. webserver
  3. [root@myserver ~]# docker ps
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. [root@myserver ~]# docker ps -a
  6. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  7. 8d485b358cc6 nginx "/docker-entrypoint.…" 33 minutes ago Exited (137) 7 seconds ago webserver
  8. [root@myserver ~]#

top 查看容器进程

  1. [root@myserver ~]# docker top webserver
  2. UID PID PPID C STIME TTY TIME CMD
  3. root 7153 7136 0 22:30 pts/0 00:00:00 nginx: master process nginx -g daemon off;
  4. 101 7211 7153 0 22:30 pts/0 00:00:00 nginx: worker process
  5. [root@myserver ~]# docker top webserver 7153
  6. PID TTY STAT TIME COMMAND
  7. 7153 pts/0 Ss+ 0:00 nginx: master process nginx -g daemon off;
  8. [root@myserver ~]#

exec 进入容器执行命令

  1. [root@myserver ~]# docker exec -it webserver bash
  2. root@8d485b358cc6:/# ls
  3. curl 访问服务器nginx 成功

port 显示容器端口绑定信息

  1. [root@myserver ~]# docker port webserver
  2. 80/tcp -> 0.0.0.0:8000

cp 文件复制

  1. [root@myserver ~]# docker cp /etc/hosts webserver:/tmp
  2. [root@myserver ~]# docker exec -it webserver ls /tmp
  3. hosts
  4. [root@myserver ~]# docker cp webserver:/tmp/hosts ./
  5. [root@myserver ~]# ls hosts
  6. hosts

diff 容器文件系统发生的变化

  1. [root@myserver ~]# docker diff webserver
  2. C /etc
  3. C /etc/nginx
  4. C /etc/nginx/conf.d
  5. C /etc/nginx/conf.d/default.conf
  6. C /run
  7. A /run/nginx.pid
  8. C /tmp
  9. A /tmp/hosts
  10. C /var
  11. C /var/cache
  12. C /var/cache/nginx
  13. A /var/cache/nginx/fastcgi_temp
  14. A /var/cache/nginx/proxy_temp
  15. A /var/cache/nginx/scgi_temp
  16. A /var/cache/nginx/uwsgi_temp
  17. A /var/cache/nginx/client_temp

export 导出容器文件系统到本地归档

  1. [root@myserver ~]# docker export -o test.tar webserver
  2. [root@myserver ~]# mkdir docker
  3. [root@myserver ~]# mv test.tar docker/
  4. [root@myserver ~]# cd docker/
  5. [root@myserver docker]# ls
  6. test.tar
  7. [root@myserver docker]# tar xf test.tar
  8. l[root@myserver docker]# ls
  9. bin dev docker-entrypoint.sh home lib64 mnt proc run srv test.tar usr
  10. boot docker-entrypoint.d etc lib media opt root sbin sys tmp var
  11. [root@myserver docker]# cd tmp/
  12. [root@myserver tmp]# ls
  13. hosts

import 导入压缩文件到镜像

  1. [root@myserver docker]# ls
  2. bin dev docker-entrypoint.sh etc lib media opt root sbin sys tmp var
  3. boot docker-entrypoint.d Dockerfile home lib64 mnt proc run srv test.tar usr
  4. [root@myserver docker]# docker import test.tar webserver:v2
  5. sha256:5aa7a154ce2f07e8dc94d331d8809ea40ea5fab4ffa8935e2092771f863e3c0f
  6. [root@myserver docker]# docker history webserver:v2
  7. IMAGE CREATED CREATED BY SIZE COMMENT
  8. 5aa7a154ce2f 15 seconds ago 130MB Imported from -
  9. [root@myserver docker]#

history 查看镜像的更新历史

  1. [root@myserver ~]# docker history nginx
  2. IMAGE CREATED CREATED BY SIZE COMMENT
  3. 2622e6cca7eb 4 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
  4. <missing> 4 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGTERM 0B
  5. <missing> 4 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B
  6. <missing> 4 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["/docker-entr… 0B
  7. <missing> 4 weeks ago /bin/sh -c #(nop) COPY file:cc7d4f1d03426ebd… 1.04kB
  8. <missing> 4 weeks ago /bin/sh -c #(nop) COPY file:b96f664d94ca7bbe… 1.96kB
  9. <missing> 4 weeks ago /bin/sh -c #(nop) COPY file:d68fadb480cbc781… 1.09kB
  10. <missing> 4 weeks ago /bin/sh -c set -x && addgroup --system -… 62.9MB
  11. <missing> 4 weeks ago /bin/sh -c #(nop) ENV PKG_RELEASE=1~buster 0B
  12. <missing> 4 weeks ago /bin/sh -c #(nop) ENV NJS_VERSION=0.4.1 0B
  13. <missing> 4 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.19.0 0B
  14. <missing> 4 weeks ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… 0B
  15. <missing> 4 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
  16. <missing> 4 weeks ago /bin/sh -c #(nop) ADD file:4d35f6c8bbbe6801c… 69.2MB

login /logout Docker registry

  1. [root@myserver ~]# docker login
  2. Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
  3. Username: devopsvip
  4. Password:
  5. WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
  6. Configure a credential helper to remove this warning. See
  7. https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  8. Login Succeeded
  9. [root@myserver ~]#
  10. [root@myserver ~]# docker logout
  11. Removing login credentials for https://index.docker.io/v1/

search 查找镜像

  1. docker search hello-world

pull 下载镜像(docker hub)

  1. [root@myserver ~]# docker pull hello-world
  2. Using default tag: latest
  3. latest: Pulling from library/hello-world
  4. 0e03bdcc26d7: Pull complete
  5. Digest: sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9
  6. Status: Downloaded newer image for hello-world:latest
  7. docker.io/library/hello-world:latest

images 查看本地的镜像

  1. [root@myserver ~]# docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. hello-world latest bf756fb1ae65 6 months ago 13.3kB

tag重命名

  1. [root@myserver ~]# docker tag hello-world:latest devopsvip/docker:latest
  2. [root@myserver ~]# docker images
  3. REPOSITORY TAG IMAGE ID CREATED SIZE
  4. nginx latest 2622e6cca7eb 4 weeks ago 132MB
  5. centos 7 b5b4d78bc90c 2 months ago 203MB
  6. devopsvip/docker latest bf756fb1ae65 6 months ago 13.3kB
  7. hello-world latest bf756fb1ae65 6 months ago 13.3kB

push 上传镜像到镜像仓库

  1. [root@myserver ~]# docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. nginx latest 2622e6cca7eb 4 weeks ago 132MB
  4. centos 7 b5b4d78bc90c 2 months ago 203MB
  5. devopsvip/docker latest bf756fb1ae65 6 months ago 13.3kB
  6. hello-world latest bf756fb1ae65 6 months ago 13.3kB
  7. [root@myserver ~]# docker push devopsvip/docker:latest
  8. The push refers to repository [docker.io/devopsvip/docker]
  9. 9c27e219663c: Preparing
  10. denied: requested access to the resource is denied
  11. [root@myserver ~]# docker login
  12. Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
  13. Username: devopsvip
  14. Password:
  15. WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
  16. Configure a credential helper to remove this warning. See
  17. https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  18. Login Succeeded
  19. [root@myserver ~]# docker push devopsvip/docker:latest
  20. The push refers to repository [docker.io/devopsvip/docker]
  21. 9c27e219663c: Mounted from library/hello-world
  22. latest: digest: sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042 size: 525

rmi 删除镜像

  1. [root@myserver ~]# docker rmi devopsvip/docker:latest
  2. Untagged: devopsvip/docker:latest
  3. Untagged: devopsvip/docker@sha256:90659bf80b44ce6be8234e6ff90a1ac34acbeb826903b02cfa0da11c82cbc042
  4. [root@myserver ~]# docker images
  5. REPOSITORY TAG IMAGE ID CREATED SIZE
  6. nginx latest 2622e6cca7eb 4 weeks ago 132MB
  7. centos 7 b5b4d78bc90c 2 months ago 203MB
  8. hello-world latest bf756fb1ae65 6 months ago 13.3kB
  9. [root@myserver ~]#

commit 将容器变化为镜像

  1. [root@myserver ~]# docker commit -a "devopsvipxx" -m "hhahh" webserver webserver:v1
  2. sha256:d315f2bb406067262798358e85aaef06f2d99dfc1adbc8380dd9cc5d0f809e76
  3. [root@myserver ~]# docker history webserver:v1
  4. IMAGE CREATED CREATED BY SIZE COMMENT
  5. d315f2bb4060 2 seconds ago nginx -g daemon off; 1.39kB hhahh
  6. 2622e6cca7eb 4 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B
  7. <missing> 4 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGTERM 0B
  8. <missing> 4 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B
  9. <missing> 4 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["/docker-entr… 0B
  10. <missing> 4 weeks ago /bin/sh -c #(nop) COPY file:cc7d4f1d03426ebd… 1.04kB
  11. <missing> 4 weeks ago /bin/sh -c #(nop) COPY file:b96f664d94ca7bbe… 1.96kB
  12. <missing> 4 weeks ago /bin/sh -c #(nop) COPY file:d68fadb480cbc781… 1.09kB
  13. <missing> 4 weeks ago /bin/sh -c set -x && addgroup --system -… 62.9MB
  14. <missing> 4 weeks ago /bin/sh -c #(nop) ENV PKG_RELEASE=1~buster 0B
  15. <missing> 4 weeks ago /bin/sh -c #(nop) ENV NJS_VERSION=0.4.1 0B
  16. <missing> 4 weeks ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.19.0 0B
  17. <missing> 4 weeks ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… 0B
  18. <missing> 4 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
  19. <missing> 4 weeks ago /bin/sh -c #(nop) ADD file:4d35f6c8bbbe6801c… 69.2MB

build 构建镜像

  1. Dockerfile
  2. FROM nginx
  3. docker build .
  4. docker build -f aa/Dockerfile .
  5. [root@myserver docker]# docker build .
  6. Sending build context to Docker daemon 269.2MB
  7. Step 1/1 : FROM webserver:v1
  8. ---> d315f2bb4060
  9. Successfully built d315f2bb4060
  10. [root@myserver docker
  11. [root@myserver docker]# docker build -t webserver:v2 .
  12. Sending build context to Docker daemon 269.2MB
  13. Step 1/1 : FROM webserver:v1
  14. ---> d315f2bb4060
  15. Successfully built d315f2bb4060
  16. Successfully tagged webserver:v2

load 通过归档文件加载镜像

save 将镜像制作归档文件

  1. [root@myserver docker]# docker save -o webserver-v2.tar webserver:v2
  2. [root@myserver docker]# docker rmi webserver:v2
  3. Untagged: webserver:v2
  4. Deleted: sha256:5aa7a154ce2f07e8dc94d331d8809ea40ea5fab4ffa8935e2092771f863e3c0f
  5. Deleted: sha256:eef9ee7ccbdfd908b67057aa17a6d7292bbc0e7cb04a57896d25ce24a6e115b7
  6. [root@myserver docker]# docker load -i webserver-v2.tar
  7. eef9ee7ccbdf: Loading layer 134.6MB/134.6MB
  8. Loaded image: webserver:v2
  9. [root@myserver docker]# docker images
  10. REPOSITORY TAG IMAGE ID CREATED SIZE
  11. webserver v2 5aa7a154ce2f 18 hours ago 130MB
  12. webserver v1 d315f2bb4060 18 hours ago 132MB
  13. <none> <none> 46a71bf11111 18 hours ago 132MB
  14. <none> <none> 5ab53db1229d 18 hours ago 132MB
  15. nginx latest 2622e6cca7eb 4 weeks ago 132MB
  16. centos 7 b5b4d78bc90c 2 months ago 203MB
  17. devopsvip/docker latest bf756fb1ae65 6 months ago 13.3kB
  18. hello-world latest bf756fb1ae65 6 months ago 13.3kB
  19. [root@myserver docker]#

create 创建一个容器

  1. [root@myserver docker]# docker create --name webnewserver nginx
  2. bbc81d2c72831167da41a6ccda4e06e6efe51eba81cf6daace0f49e5815e88db
  3. [root@myserver docker]# docker ps
  4. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  5. [root@myserver docker]# docker ps -a
  6. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  7. bbc81d2c7283 nginx "/docker-entrypoint.…" 17 seconds ago Created webnewserver
  8. d2813b963195 nginx "/docker-entrypoint.…" 19 hours ago Created youthful_ramanujan
  9. 4fe81888bdd1 nginx "/docker-entrypoint.…" 24 hours ago Exited (255) 11 minutes ago 0.0.0.0:8000->80/tcp webserver
  10. [root@myserver docker]# docker start webnewserver
  11. webnewserver
  12. [root@myserver docker]# docker ps
  13. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  14. bbc81d2c7283 nginx "/docker-entrypoint.…" 41 seconds ago Up 4 seconds 80/tcp webnewserver
  15. [root@myserver docker]#

update 更新容器的配置

  1. [root@myserver docker]# docker update --memory 1G --memory-swap 1G webaserver
  2. [root@myserver docker]# docker stats webaserver
  3. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
  4. bd8375d39858 webaserver 0.00% 2.445MiB / 1GiB 0.24% 3.69kB / 0B

Dockerfile构建镜像

Dockerfile: 用来构建镜像的文件,文件中包含指令。docker build

  1. docker build -t image:v1.0 .
  2. docker build -t image:v1.0 -f /opt/dockerfile .
  • -f 指定dockerfile
  • -t 指定镜像名称

3.2 Kubernetes基础

master:控制节点 node: 工作节点
image.png

Namespace
Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。 这些虚拟集群被称为命名空间。Kubernetes中默认的Namespace是default。

kubectl get namespace 可以查看当前集群的所有名称空间

image.png


Volume

  • emptyDir: 空目录
  • hostPath: 本地目录
  • nfs: 网络存储

image.png


Deployment

一个部署控制器提供声明更新pod。在Deployment对象中描述所需的状态,然后Deployment控制器将实际状态以受控的速率更改为所需的状态。可以定义部署以创建新的副本集,或删除现有部署并在新部署中采用其所有资源。


Service
服务发现机制。 Kubernetes为Pods提供自己的IP地址和一组Pod的单个DNS名称,并且可以在它们之间进行负载平衡。

image.png


3.3 部署与发布策略

滚动更新

  1. apiVersion: apps/v1beta2
  2. kind: Deployment
  3. metadata:
  4. name: nginx
  5. labels:
  6. app: nginx
  7. spec:
  8. replicas: 1
  9. selector:
  10. matchLabels:
  11. app: nginx
  12. strategy:
  13. type: RollingUpdate
  14. rollingUpdate:
  15. maxUnavailable: 1 ## 最多1个pod处于不可工作状态
  16. maxSurge: 2 ## 升级时可以比预期多出2个pod
  17. minReadySeconds: 5 ## 容器启动后等待5秒

蓝绿发布

创建新的部署,然后修改service的标签来将流量指向新的部署。

  1. [root@master b-g]# kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. nginxapp-1.19-bdb8dc6c4-2jfsw 1/1 Running 0 12m
  4. nginxapp-1.19-bdb8dc6c4-79qrh 1/1 Running 0 12m
  5. nginxapp-1.19-bdb8dc6c4-hbwkx 1/1 Running 0 12m
  6. nginxapp-1.20-786464458-4zh5t 1/1 Running 0 91s
  7. nginxapp-1.20-786464458-5bfwq 1/1 Running 0 91s
  8. nginxapp-1.20-786464458-fwgxb 1/1 Running 0 91s

v1.19-blue.yaml

  1. kind: Deployment
  2. apiVersion: apps/v1
  3. metadata:
  4. labels:
  5. k8s-app: nginxapp
  6. version: "1.19"
  7. name: nginxapp-1.19
  8. namespace: default
  9. spec:
  10. replicas: 3
  11. revisionHistoryLimit: 10
  12. selector:
  13. matchLabels:
  14. k8s-app: nginxapp
  15. version: "1.19"
  16. template:
  17. metadata:
  18. labels:
  19. k8s-app: nginxapp
  20. version: "1.19"
  21. namespace: default
  22. name: nginxapp
  23. spec:
  24. containers:
  25. - name: nginxapp
  26. image: nginx:1.19
  27. imagePullPolicy: IfNotPresent
  28. ports:
  29. - containerPort: 80
  30. name: web

service.yaml

  1. kind: Service
  2. apiVersion: v1
  3. metadata:
  4. name: nginxapp
  5. namespace: default
  6. spec:
  7. ports:
  8. - name: web
  9. port: 80
  10. targetPort: 80
  11. selector:
  12. k8s-app: nginxapp
  13. version: "1.19"

v1.20-green.yaml

  1. kind: Deployment
  2. apiVersion: apps/v1
  3. metadata:
  4. labels:
  5. k8s-app: nginxapp
  6. version: "1.20"
  7. name: nginxapp-1.20
  8. namespace: default
  9. spec:
  10. replicas: 3
  11. revisionHistoryLimit: 10
  12. selector:
  13. matchLabels:
  14. k8s-app: nginxapp
  15. version: "1.20"
  16. template:
  17. metadata:
  18. labels:
  19. k8s-app: nginxapp
  20. version: "1.20"
  21. namespace: default
  22. name: nginxapp
  23. spec:
  24. containers:
  25. - name: nginxapp
  26. image: nginx:20
  27. imagePullPolicy: IfNotPresent
  28. ports:
  29. - containerPort: 80
  30. name: web

启动busybox容器调试

  1. kubectl run --restart=Never -it --image \
  2. infoblox/dnstools dnstools

灰度发布

https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary

nginx-1.19

  1. kind: Deployment
  2. apiVersion: apps/v1
  3. metadata:
  4. labels:
  5. k8s-app: nginxapp
  6. version: "1.19"
  7. name: nginxapp-1-19
  8. namespace: default
  9. spec:
  10. replicas: 3
  11. revisionHistoryLimit: 10
  12. selector:
  13. matchLabels:
  14. k8s-app: nginxapp
  15. version: "1.19"
  16. template:
  17. metadata:
  18. labels:
  19. k8s-app: nginxapp
  20. version: "1.19"
  21. namespace: default
  22. name: nginxapp
  23. spec:
  24. containers:
  25. - name: nginxapp
  26. image: nginx:1.19
  27. imagePullPolicy: IfNotPresent
  28. ports:
  29. - containerPort: 80
  30. name: web
  31. ---
  32. kind: Service
  33. apiVersion: v1
  34. metadata:
  35. name: nginxapp-1-19
  36. namespace: default
  37. spec:
  38. ports:
  39. - name: web
  40. port: 80
  41. targetPort: 80
  42. selector:
  43. k8s-app: nginxapp
  44. version: "1.19"

nginx-1.20

  1. kind: Deployment
  2. apiVersion: apps/v1
  3. metadata:
  4. labels:
  5. k8s-app: nginxapp
  6. version: "1.20"
  7. name: nginxapp-1-20
  8. namespace: default
  9. spec:
  10. replicas: 3
  11. revisionHistoryLimit: 10
  12. selector:
  13. matchLabels:
  14. k8s-app: nginxapp
  15. version: "1.20"
  16. template:
  17. metadata:
  18. labels:
  19. k8s-app: nginxapp
  20. version: "1.20"
  21. namespace: default
  22. name: nginxapp
  23. spec:
  24. containers:
  25. - name: nginxapp
  26. image: nginx:1.20
  27. imagePullPolicy: IfNotPresent
  28. ports:
  29. - containerPort: 80
  30. name: web
  31. ---
  32. kind: Service
  33. apiVersion: v1
  34. metadata:
  35. name: nginxapp-1-20
  36. namespace: default
  37. spec:
  38. ports:
  39. - name: web
  40. port: 80
  41. targetPort: 80
  42. selector:
  43. k8s-app: nginxapp
  44. version: "1.20"

创建资源:

  1. [root@master ingress-gray]# kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. nginxapp-1-19-bdb8dc6c4-6pd66 1/1 Running 0 4s
  4. nginxapp-1-19-bdb8dc6c4-8fqj6 1/1 Running 0 4s
  5. nginxapp-1-19-bdb8dc6c4-txvwp 1/1 Running 0 4s
  6. nginxapp-1-20-786464458-2hp6p 1/1 Running 0 5s
  7. nginxapp-1-20-786464458-6t4sv 1/1 Running 0 5s
  8. nginxapp-1-20-786464458-psmwf 1/1 Running 0 5s
  9. [root@master ingress-gray]# kubectl get service
  10. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  11. kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 266d
  12. nginxapp-1-19 ClusterIP 10.1.215.94 <none> 80/TCP 13s
  13. nginxapp-1-20 ClusterIP 10.1.163.181 <none> 80/TCP 14s
  14. spinnaker-demo NodePort 10.1.86.122 <none> 80:30010/TCP 226d
  15. waypoint NodePort 10.1.5.220 <none> 9701:37798/TCP,9702:17531/TCP 168d

创建ingress

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: nginxapp-ingress
  5. namespace: default
  6. spec:
  7. rules:
  8. - host: nginxapp.devops.com
  9. http:
  10. paths:
  11. - path: /
  12. backend:
  13. serviceName: nginxapp-1-19
  14. servicePort: 80

测试:

  1. ## 编辑hosts文件
  2. 192.168.10.100 nginxapp.devops.com
  3. for i in {1..10};do curl nginxapp.devops.com;done

基于权重的发布

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: nginxapp-canary
  5. namespace: default
  6. annotations:
  7. kubernetes.io/ingress.class: nginx
  8. nginx.ingress.kubernetes.io/canary: "true"
  9. nginx.ingress.kubernetes.io/canary-weight: "10"
  10. spec:
  11. rules:
  12. - host: nginxapp.devops.com
  13. http:
  14. paths:
  15. - path: /
  16. backend:
  17. serviceName: nginxapp-1-20
  18. servicePort: 80

Header报头流量分发

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: nginxapp-canary
  5. namespace: default
  6. annotations:
  7. kubernetes.io/ingress.class: nginx
  8. nginx.ingress.kubernetes.io/canary: "true"
  9. nginx.ingress.kubernetes.io/canary-by-header: "Region"
  10. nginx.ingress.kubernetes.io/canary-by-header-value: "bj"
  11. spec:
  12. rules:
  13. - host: nginxapp.devops.com
  14. http:
  15. paths:
  16. - path: /
  17. backend:
  18. serviceName: nginxapp-1-20
  19. servicePort: 80
  1. for i in {1..10};do curl -H "region: bj" nginxapp.devops.com;done

根据cookie流量分发

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. name: nginxapp-canary
  5. namespace: default
  6. annotations:
  7. kubernetes.io/ingress.class: nginx
  8. nginx.ingress.kubernetes.io/canary: "true"
  9. nginx.ingress.kubernetes.io/canary-by-cookie: "from"
  10. spec:
  11. rules:
  12. - host: nginxapp.devops.com
  13. http:
  14. paths:
  15. - path: /
  16. backend:
  17. serviceName: nginxapp-1-20
  18. servicePort: 80
  1. [root@master ingress-gray]# curl nginxapp.devops.com --cookie "from=always"
  2. <h1>Welcome to nginx!</h1>
  3. [root@master ingress-gray]# curl nginxapp.devops.com --cookie "from=a"
  4. green
  5. [root@master ingress-gray]# curl nginxapp.devops.com --cookie "from=a"
  6. green

3.4 Kubectl

参考:https://kubernetes.io/zh/docs/reference/kubectl/overview/

升级

  1. kubectl create -f xxx.yaml
  2. kubectl apply -f xxx.yaml

回滚

  1. ## 查看历史
  2. kubectl rollout history deployment/anyops-devopsdocker-ui
  3. ## 查看具体某一个历史版本信息
  4. kubectl rollout history deployment/anyops-devopsdocker-ui --revision=2
  5. ## 回滚上个版本
  6. kubectl rollout undo deployment/anyops-devopsdocker-ui -n anyops
  7. ## 回滚指定版本
  8. kubectl rollout undo deployment/nginx --to-revision=2

3.5 Helm

下载连接:https://github.com/helm/helm/releases 一旦你成功安装了Helm客户端,就可以继续使用Helm管理chart和 添加稳定的仓库。

使用Nexus配置helm chart仓库 https://cloud.tencent.com/developer/article/1647771

基本概念

Chart 代表着 Helm 包。它包含在 Kubernetes 集群内部运行应用程序,工具或服务所需的所有资源定义。
Repository(仓库) 是用来存放和共享 charts 的地方。
Release 是运行在 Kubernetes 集群中的 chart 的实例。

Helm 安装 charts 到 Kubernetes 集群中,每次安装都会创建一个新的 release。你可以在 Helm 的 chart repositories 中寻找新的 chart。

常用命令

  1. ## 查找chart
  2. helm search hub artifact hub中搜索
  3. helm search repo 从本地的仓库搜索
  4. ## 仓库管理
  5. helm repo list
  6. helm repo add
  7. helm repo add dev https://example.com/dev-charts
  8. helm search repo dev
  9. ## 安装chart
  10. helm install RELEASE_NAME CHART_NAME
  11. helm install happy-panda bitnami/wordpress
  12. ### 本地 chart 压缩包
  13. helm install foo foo-0.1.1.tgz
  14. ### 解压后的 chart 目录
  15. helm install foo path/to/foo
  16. ### 完整的 URL
  17. helm install foo https://example.com/charts/foo-1.2.3.tgz
  18. ## 追踪release的状态
  19. helm status happy-panda
  20. ## 查看chart中的可配置选项
  21. helm show values CHART_NAME
  22. helm install -f values.yaml bitnami/wordpress --generate-name
  23. 数据传递:
  24. --values /-f 指定yaml文件
  25. --set 命令行方式对值进行覆盖
  26. ## 升级
  27. helm upgrade -f panda.yaml happy-panda bitnami/wordpress
  28. ## 回滚
  29. helm history [RELEASE] 命令来查看一个特定 release 的修订版本号。
  30. helm rollback
  31. helm rollback [RELEASE] [REVISION]

自定义charts
helm create RELEASE_NAME
helm package nginxapp
helm install nginxapp ./nginxapp-0.1.0.tgz


工作流设计: 前端项目演示

  • CI流水线:
    • 构建docker镜像
    • 上传到镜像仓库
    • 更新values.yaml 文件
  • CD流水线:
    • 下载chart代码
    • helm package
    • helm install || helm upgrade
    • helm rollback || helm deploy

image.png

  • V1 旧版本正常运行中, 用户请求流量都在V1
  • V2 新版本开始发布, ingress控制, 通过header/cookie/weight 将一部分流量引到V2 10%
  • 更新Ingress , 流量扩大到30%
  • 更新Ingress , 流量扩大到60%
  • 更新Ingress , 流量扩大到90%
  • 更新Ingress , 流量扩大到100%
  • 此时测试没问题, 用V2 helm chart 部署替换V1旧版本。

FAQs

image.png