上手 Docker 容器,不应该是个问题

在微服务时代,服务数量及规模越来越大,服务的部署及运维的模式如果仍然采用传统方式就会大大增加运维成本。所以微服务时代的运维方式一定是Devops模式,通过构建自动化运维发布平台来打通产品、开发、测试及运维流程,从而整体上提升研发效能,而这也是目前大部分公司正在做的事情。

随着以Docker为代表的容器化技术的普及,目前Devops实践大多会采用容器(如Docker、K8s)这样的方式来作为微服务应用部署运行的载体,并通过容器的弹性扩展来实现快速扩容和缩容,从而更快地响应业务、更好地利用资源。

目前Devops*流行的部署方案是基于K8s的集群方案,但是它本身也是基于Docker容器技术的,所以在接触K8s技术之前,先通过本文了解下Docker及基于Docker的容器化部署。

%title插图%num

Docker的基本概念

Docker是一个开源的应用容器引擎,也是目前*流程的应用部署方式,通过它可以把应用及其依赖打包到一个可移植的镜像中,然后利用Docker提供的部署机制将其发布至任意安装了Docker容器的系统环境中。从使用角度主要需要理解一下几个要点如图所示:

%title插图%num

如上图所示,理解Docker的使用方式需要掌握以下几个概念:

  • Image(镜像):它是一个可执行文件,包含应用代码、依赖库、运行环境(如JRE等)以及环境变量及配置等信息,通过镜像可以启动一个应用,镜像的构建过程通过Dockefile文件描述。
  • Container(容器):使用Image启动的一个进程实例,它与镜像之间为一对多的关系,一个镜像可以启动多个容器实例。
  • Service(服务):一组提供对外服务的Container,这些Container使用同一个Image镜像,它与镜像为一对一、与容器为一对多的关系,Service由docker-compose文件定义。
  • Stack(应用):一组Service,相互协作对外提供服务,可以看作是一个完整的应用,在一些复杂的场景中会拆分为多个Stack,由docker-compose构建。

%title插图%num

Docker部署一个Spring Boot服务

为了更进一步加深对上述概念的理解,这里以一个Spring Boot应用为例演示如何通过Docker部署一个Spring Boot服务。这里可以通过IDE创建一个简单的Spring Boot应用并写一个测试接口,如下图所示:

%title插图%num

以上为通过IDEA创建的一个*为简单的Spring Boot应用程序,运行后启动服务可以通过端口访问测试接口,接下来使用Docker部署该服务,步骤如下:

  创建Dockerfile文件构建Docker镜像

按照前面Docker的介绍,如果要让Spring Boot程序运行在Docker容器上,首先需要构建Docker镜像,而构建的过程则需要通过Dockerfile文件来描述。例如在项目src/main/docker目录创建Dockerfile文件,代码如下:

  1. 1FROM java:8
  2. 2VOLUME /tmp
  3. 3RUN mkdir /app
  4. 4ADD springboot-1.0-SNAPSHOT.jar /app/springboot.jar
  5. 5ADD runboot.sh /app/
  6. 6RUN bash -c ‘touch /app/springboot.jar’
  7. 7WORKDIR /app
  8. 8RUN chmod a+x runboot.sh
  9. 9EXPOSE 9090
  10. 10CMD /app/runboot.sh
上述Dockerfile文件定义了运行的基础信息为JDK1.8、容器运行的目录为/app、并添加了所需的Jar包等信息,*后定义了要执行的命令为“/app/runboot.sh”脚本。runboot.sh脚本代码如下:
  1. 1sleep 10
  2. 2java -Djava.security.egd=file:/dev/./urandom -jar  /app/springboot.jar

这里打包Spring Boot应用Docker镜像的Dockerfile文件就定义好了,为了能在Maven项目中执行Docker镜像构建命令,还需要在项目pom.xml文件添加Maven Build插件信息,代码如下:

  1. 1<!–Docker Maven插件依赖–>
  2. 2<plugin>
  3. 3    <groupId>com.spotify</groupId>
  4. 4    <artifactId>docker-maven-plugin</artifactId>
  5. 5    <configuration>
  6. 6        <imageName>${project.name}:${project.version}</imageName>
  7. 7        <dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
  8. 8        <skipDockerBuild>false</skipDockerBuild>
  9. 9        <resources>
  10. 10            <resource>
  11. 11                <directory>${project.build.directory}</directory>
  12. 12                <include>${project.build.finalName}.jar</include>
  13. 13            </resource>
  14. 14        </resources>
  15. 15    </configuration>
  16. 16</plugin>

接下来可以通过Maven命令构建Spring Boot应用Docker镜像,命令如下:

  1. 1mvn clean package docker:build

运行成功可以看到本地Docker仓库中镜像信息,命令如下:

%title插图%num

这表示Spring Boot程序的Docker镜像已打好,需要说明的是以上命令运行是需要你的系统已经安装Docker容器运行环境。

  创建docker-compose.yml文件

有了Docker镜像,如何将镜像作为容器启动以及该镜像中启动那些服务、它的资源限制及网络使用什么方式,这些都是docker-compose文件定义的,其代码如下:

  1. 1version: ‘3.2’
  2. 2services:
  3. 3  springboot:
  4. 4    image: springboot:1.0-SNAPSHOT
  5. 5    hostname: springboot
  6. 6    environment:
  7. 7      – SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-debug}
  8. 8    ports:
  9. 9      – “9999:9090”
  10. 10    networks:
  11. 11      – mynet
  12. 12networks:
  13. 13  mynet:
  14. 14    external: true

在上述docker compose文件中定义了一个springboot服务,然后针对该服务描述了其所使用的Docker镜像、环境变量参数、容器端口映射及网络等信息。需要说明的是services下面还可以定义服务,stack(应用)与service(服务)的关系在docker-compose中是一对多的关系,只是这里暂时没有需要定义其他服务。

启动Docker容器实现应用容器部署

通过上述准备,此时就可以通过docker-compose启动Spring Boot应用的Docker镜像,目录切换到src/main/docker目录,执行如下命令:

  1. 1$ docker-compose up -d
  2. 2Creating docker_springboot_1 … done

此时应用就已经通过Docker容器部署了,可以通过如下命令进行查看:

  1. 1$ docker ps
  2. 2CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                                                                      NAMES
  3. 34117e4a8963e        springboot:1.0-SNAPSHOT   “/bin/sh -c /app/run…”   5 seconds ago       Up 3 seconds        9090/tcp, 0.0.0.0:9999->9999/tcp                                           docker_springboot_1

到这里就大功告成了,访问9999端口就能够访问到Docker容器中的Spring Boot服务了。