docker实现DevOps自动化工作流,思维决定docker快而稳

2023年 8月 14日 25.8k 0

本本分分做人,踏踏实实做事!!!

前言

公司的项目小而杂,每个项目都需要经历一遍部署的烦恼。团队来新人重复的配置又得一遍又一遍的传授。类似这种重复重复再重复的工作,简直让人哭笑不得!!!

场景

  • 为了能够实现项目工程化,我们绝对引入 docker 这项技术. Docker 是一个用于 构建运行传送 应用程序的平台

20230807-182409065.png

  • 基于 docker 的可移植性,我们可以将我们项目完整的生命周期编写成一个 docker 镜像,这样我们就完美规避了重复的工作了。
  • 目前主流的结构都是前后端分离架构,一个空服务器想要完整的运行起项目必须保证服务器上安装的 node 、java 等基础环境。除此之外后端为了能够存储数据还需要安装 mysql. 为了能够加快接口响应时间,我们还需要引入类似 redis 的 nosql 存储服务器。为了能够统一我们对外的接口,正常我们还需要使用 nginx 进行资源代理。这些步骤虽然没有太难的操作,但是将时间浪费在这些软件的安装配置上,难免还是有点大材小用了。
  • 有了 docker 我们就能够将上述的步骤记录下来,让 docker 自动帮我们实现这些死板的操作。上面的流程自动化执行的过程我们称之为项目工程化。从而实现我们的项目克隆孪生技术。

横向对比

  • 很多人提到 docker 第一反应就是虚拟。实际上 docker 和我们熟知的虚拟机有很大不同。最直观的体验就是虚拟机运行起来特别笨重,同一台电脑上开两个虚拟机就很卡,但是却可以开 10~20 个 docker 容器。这取决于它的第一依赖的共用性。

  • 我们熟知的虚拟机主要是 vmwarevirtualboxparales desktop 等 , 他们的实现逻辑主要依赖于虚拟化(Hypervior)技术

20230807-183451236.png

  • 我们可以非常清楚的看出来,每个虚拟机都会开辟一个操作系统及其附属服务。这也是导致虚拟机笨重的原因。而 docker 确实共用同一个物理服务器的 OS

20230807-183805244.png

原理

  • docker 的架构属于 To C 结构。在我们安装 docker 的时候实际上会出现一个 docker daemon 后台常驻进程。客户端就是我们平时使用的 docker 命令。 docker images docker pull docker run `
  • docker 为了方便我们快速构建我们的镜像,官方提供了一个镜像仓库,我们在构建自定义镜像时就无需从底层开始构建了。比如我们构建一个 Springboot 镜像完全直接依赖 jdk 镜像即可。我们完全不需要关系底层 linux 服务这些问题。因为这些依赖 JDK 镜像里已经处理过了。

具体案例

  • 说了这么多,我们该如何构建一个我们自己的镜像呢?首先我们需要一个 dockerfile 文件。上面我们也提到了 Springboot 项目我们只需要依赖 JDK 镜像就可以了。下面是我们的 dockerfile
FROM openjdk:11-jre 
MAINTAINER zxhtom 
WORKDIR / 
ADD target/demo.jar app.jar 
EXPOSE 9999 
ENTRYPOINT ["java", "-jar"] 
CMD ["app.jar"]
  • FROM openjdk:11-jre,网上大多都是使用 openjdk ,我也不知道为啥。这里具体能从哪些开始构建,我们可以访问 Explore Docker's Container Image Repository | Docker Hub 得到镜像名称。

  • MAINTAINER zxhtom,创建镜像的作者, 请记住我 zxhtom

  • WORKDIR / : 可以简单理解成 docker 构建过程中命令执行的所在路径。比如系阿敏啊 ENTRYPOINT CMD 等命令执行的路径就在 WORKDIR 下。

  • ADD target/springboot-demo-helloworld.jar app.jar,表示将jar包添加到镜像中,并重命名app.jar

  • EXPOSE 9999 ,表示暴露的端口是 9999

  • ENTRYPOINT ["java","Xmx1024m", "-jar"],表示启动时运行 java -jar

  • CMD ["app.jar"],表示参数,这里是运行的具体的jar

  • 有了这些我们就可以开始构建我们的镜像了。

docker build -f dockerfile -t zxhtom-demo:1.0 .
  • 表示从当前路径开始构建 zxhtom-demo 镜像并且将版本命名为 1.0 具体的参数来自 dockerfile 文件。正常情况下 docker file 和我们项目的 pom 文件是同一层级的。如果放在其他位置对应的路径地址就可以变为对应的相对地址。

20230807-190153542.png

20230807-190035173.png

  • 构建完成之后我们就能够看到我们的镜像了。既然镜像已经有了,下面我们就开启动一个容器吧。
docker run -d -p 9999:9999 --name zxhtom zxhtom-demo:1.0

20230807-190537912.png

  • 启动之后我们可以通过 docker logs 查看启动日志。

20230807-190626865.png

  • 总之到这里我们的镜像制作就完成了。我们就可以直接将镜像上传到仓库或者私服仓库中。其他环境需要部署我们的 springboot 项目只需要通过 docker 启动一下即可。当然这里为了演示方便我并没有添加其他的依赖。比如 node 、mysql 、redis 等依赖。

多镜像部署

  • 随着项目的演进,我们大多都是分布式项目,这也就意味着我们同时需要部署多个 spring Boot 项目,对于多个镜像每次都需要进行启动管理这无疑也是重复且枯燥的。docker 既然帮助我们解决了重复劳动的问题,那么他就帮我们帮到底。docker 官方推出了 docker-compose 。docker-compose 负责实现对 Docker 容器集群的快速编排。它是一个定义和运行多容器的 docker 应用工具。使用 compose,你能通过 YMAL 文件配置你自己的服务,然后通过一个命令,你能使用配置文件创建和运行所有的服务。重点可以启动多个容器!
  • 有了 docker-compose 我们真正做到项目的一键管理。我们只需要对 compose 的配置文件进行对每个镜像的启动配置。我们就能将多个镜像打包处理。下面是我个人配置的一个 es集群配置
version: '3.8'
services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02,es03
      - http.cors.enabled=true
      - http.cors.allow-origin=*
      - cluster.initial_master_nodes=es01
      - node.master=true
      - network.host=es01
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - ./data/es01:/usr/share/elasticsearch/data
      - ./plugins:/usr/share/elasticsearch/plugins
    ulimits:
      memlock:
        soft: -1
        hard: -1
    ports:
      - 9200:9200
    networks:
      - elastic
  es02:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
    container_name: es02
    environment:
      - node.name=es02
      - node.master=true
      - network.host=es02
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02,es03
      - http.cors.enabled=true
      - http.cors.allow-origin=*
      - cluster.initial_master_nodes=es01
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - ./data/es02:/usr/share/elasticsearch/data
      - ./plugins:/usr/share/elasticsearch/plugins
    ulimits:
      memlock:
        soft: -1
        hard: -1
    networks:
      - elastic
  es03:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.12.1
    container_name: es03
    environment:
      - node.name=es03
      - node.master=true
      - network.host=es03
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02,es03
      - http.cors.enabled=true
      - http.cors.allow-origin=*
      - cluster.initial_master_nodes=es01
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - ./data/es03:/usr/share/elasticsearch/data
      - ./plugins:/usr/share/elasticsearch/plugins
    ulimits:
      memlock:
        soft: -1
        hard: -1
    networks:
      - elastic
  kibana:
    image: kibana:7.12.1
    container_name: kibana
    depends_on:
      - es01
    environment:
      - ELASTICSEARCH_HOSTS=http://es01:9200
    ports:
      - 5601:5601
    networks:
      - elastic

  eshead:
    image: docker.io/mobz/elasticsearch-head:5 
    container_name: eshead
    depends_on:
      - es01
    ports:
      - 9100:9100
    networks:
        - elastic
networks:
  elastic:
    driver: bridge

安全检测

  • 安全对于网站开发很重要,但是却又极不被重视的一块。不出问题各个角色都喜笑颜开,除了安全问题产品线上的每个角色都是热锅上的蚂蚁。作为一个完整的项目周期安全漏洞检测必须考虑起来。

  • 前几天项目上线就被甲方测出来网站存在严重安全问题,人家甲方直接将我们程序下架了,并让我们限期整改。这种问题如果早起能够有意识的规避就不会在甲方面前丢人了。除了问题干着急也没用。今天我们不说如何解决安全问题,重点将放在如何完善自己的安全漏洞检测

  • 耐心等待

curl -O https://engine.anchore.io/docs/quickstart/docker-compose.yaml
docker-compose up -d

devops 实践那些事

  • 上文我们介绍了 docker 起源以及原理。docker 主要是帮助我们避免重复的劳动。除此之外 docker 还提出了模块化的思想。将模块进行封装使得模块之间不会因为自身问题级联影响到其他模块的运行状态。不知道你有没有提说过 Vagrant 。其实他的功能和 docker 类似,那么为什么 docker 作为后起之秀还能这么受青睐呢?那是因为作为客户端 docker 的确和 Vagrant 功能重叠了。但是作为服务端他可以很好的和现在 CICD 进行融合。

CI (CONTINUOUS INTEGRATION) 持续集成

  • 你应该遇到过针对某个 BUG 进行修复提交了一次 fix ,但是因为自己考虑的不周全导致了另外的 BUG ,这种现象我可以说自己可是没少干。好在每次都能及时发现。从项目角度看这种现象只能说明作为程序员的我不够专业。为什么提交一个 fix 还会引发其他的 BUG 。这也说明我们对代码的质量管理没有做到位,最基本的单元测试没写才会导致这种事情的概率发生。
  • CI (CONTINUOUS INTEGRATION) 就是帮助我们实现功能验证的自动化,既然要验证那么从我们提交 fix 的那一刻开始 CI 就开始了。他会拉取我们的代码进行编译以及单元测试的验证。
  • 这个过程是自动化完成的,CI 过程结束后会将本次 CI 的结果通知到各个配置好的负责人。以便于发生故障时我们能够及时了解详情并进行修复。

CD(CONTINUOUS DEPLOYMENT) 持续部署

  • 通过 CI 过程我们已经验证通过本次的 commit ,下一步就是将本次的 commit 的功能发布到对应的环境上。这个过程的自动化就叫做持续部署。比如 jenkins 中就可以开一个管道进行发包。当然我们也可以借助 linux 的 sshpass 简单的实现一个持续部署的功能。关于 sshpass 我之前介绍过可以翻看之前文章。

CI/CD

  • CI/CD 往往是一个组合的周期,抛开 CD 那么 CI 将毫无意义,抛开 CI 那 CD 将无法实现。两者关系相辅相成,所以我们习惯称之为 CI/CD

Jenkins

  • 上面我们的 CI/CD 仅停留理论下,我们团队实际使用的是 jenkins 用来实现 CI/CD 操作。

  • 在 jenkins 中我们可以编写 Groovy 或者 pipleline 两种语法的脚本。但是往往我们的脚本功能并不是单一的。可能整个功能牵涉面很广,如果在一个脚本里编写会显得很臃肿,jenkins 提供了管道思路,让我们将脚本按步骤进行细化,每个单一的功能开辟一个管道进行执行。这点和 docker 的模块化思维不谋而合~~~。

  • Jenkins 的管道部署把部署的流程形象化成为一个长长的管道,每间隔一小段会有一个节点,也就是 Job,完成这个 Job 工作后才可以进入下一个环节

20230808-181225969.png

K8S

  • docker 和 K8s 整合能够肯方便的构建集群。集群的意义不用多说。当我们系统的压力到达一定数量级的时候,单一的服务是无法抗住压力的。部署集群就能分摊我们的服务器的压力。而 K8S 就是能够 API 分发。计算节点,通过自维护的策略来保证主机上服务的可用性,当集群控制面板发布指令后,也是异步通过 etcd 来存储和发布指令,没有集群控制链路层面的依赖

20230808-181823505.png

  • 上面这张图可能还是有点抽象。K8S 的作用就是为了能够更好的编排众多 docker 容器。你想想我们随着项目增加,会出现很多服务器,每个服务器会出现不同数量的 docker 。而在服务器层面上 docker 可能都是共同性的,如果有一个地方需要我们修改优化,每个服务都去操作这无疑也是枯燥且无味的。这个时候我们 K8S 直接管理 docker 集群。

总结

  • 不管是 docker 还是 jenkins 还是现在的 K8S ,他们的产生并不是凭空想想的,他们产生是因为前代产生一定的局限性或者给我们开发者带来一定的不便捷的情况下才产生的。目前主流应该就是 docker + jenkins 进行 CICD 操作。docker+K8S 实现容器编排。除此之外既然我们使用 docker ,那么对 docker 的监控也是非常重要的。这点我们以后再说,日后有时间我们结合 docker 的监控和项目中的日志管理监控一起谈谈监控章节吧!!!

放松一刻

Error generating daily quote

photo by Pat Whelen on Unsplash

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论