微服务项目在Docker环境下的实践(个人学习)

概述

    Docker 是一个开源应用容器(当然目前也分为CE和EE版本,不完全开源化,也存在收费版本),让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

    Docker 作为容器工具可以把:业务逻辑容器、数据库容器、储存容器、队列容器使得软件可以拆分成若干个标准化容器,然后像搭积木一样组合起来,让彼此通信,从而形成微服务。

    因此微服务很适合用 Docker 容器实现,每个容器承载一个服务。一台计算机同时运行多个容器,从而就能很轻松地模拟出复杂的微服务架构,并能体现微服务产品架构的轻量级、高并发、大数据、智能化、易维护、动态扩展的特性。

使用Docker管理项目

    本章节使用Dockerfile的方式来管理微服务项目,关于Dockerfile的指令使用或更多信息,请参照Docker操作指南

    本章节所需要的必须条件:

制作mysql镜像

前期准备

  • 创建mysql目录,该目录和jre目录平级
  • 导出192.168.7.200中的ms-user数据库,将sql脚本放到mysql目录中

mysql Dockerfile编写

在mysql目录中,创建Dockerfile文件,并将以下内容复制到Dockerfile文件中

#指定使用的镜像
FROM mysql:5.6

#指定为湖人
MAINTAINER caochuanhong@sbr-info.com

#将容器启动后,执行的脚本拷贝到容器内的/docker-entrypoint-initdb.d下,该目录会自动执行sql脚本
COPY ms-user.sql /docker-entrypoint-initdb.d

#设置mysql中的参数

#服务端到数据编码
ENV character-set-server utf8mb4
#最大数据传送量
ENV max_allowed_packet 128M
#mysql密码,可以在run指令中,附带 -e MYSQL_ROOT_PASSWORD=xxx来设置mysql密码
ENV MYSQL_ROOT_PASSWORD Admin@123

#声明容器暴漏的端口,只是声明,没有其他作用
EXPOSE 3306

构建mysql镜像

将命令行定位到mysql目录,输入

docker build -t sbr/mysql:1.0.0 .

来开始进行mysql镜像的构建

说明:

  • -t:给要构建的镜像定义一个名称
  • . 这个.代表着,让docker去读取当前目录下的Dockerfile文件来构建镜像


    5.png
6.png

此时,mysql镜像已经制作完成,可以通过以下命令来创建并启动一个容器来启动mysql服务:

docker run -d -p 3306:3306 --name mymysql e2f0dc2544d5

说明:

  • -d: 后台启动
  • -p: 第一个端口是宿主机端口,第二个端口是容器端口
  • --name: 为创建的容器设置一个名称

通过

docker ps

来查看正在运行的容器,可以发现,mysql已经跑起来了,如图所示:


7.png

通过数据库连接工具测试也可以连接到该服务。

制作redis镜像

redis Dockerfile编写

创建redis目录,该目录和mysql目录平级

在redis目录中,创建Dockerfile文件,在该文件中,输入以下内容:

#指定使用的镜像
FROM redis:4.0.2

#指定维护人
MAINTAINER caochuanhong@sbr-info.com

#声明容器暴漏的端口
EXPOSE 6379

构建redis镜像

将命令行定位到redis目录,输入

docker build -t sbr/redis:1.0.0 .

来开始进行redis镜像的构建

说明:

  • -t:给要构建的镜像定义一个名称
  • . 这个.代表着,让docker去读取当前目录下的Dockerfile文件来构建镜像
8.png

9.png

此时,redis镜像已经制作完成,可以通过以下命令来创建并启动一个容器来启动redis服务:

docker run -d -p 6379:6379 --name myredis 21690d58c82d

说明:

  • -d: 后台启动
  • -p: 第一个端口是宿主机端口,第二个端口是容器端口
  • --name: 为创建的容器设置一个名称
  • 可以在启动命令中配置 --requirepass "mypassword" 来创建redis的密码

通过

docker ps

来查看正在运行的容器,可以发现,mysql已经跑起来了,如图所示:


10.png

制作微服务项目镜像

    在制作jre基础镜像一节中,已经介绍了微服务项目必须依赖的环境的镜像制作,这一节,我们来制作微服务项目的镜像,将项目打入到镜像中,通过镜像来启动我们的项目,可以提高我们项目开发完成后很多的后续操作的效率。

前期准备

  • 将jar包复制到app目录中

微服务项目的Dockerfile编写

在app目录中创建Dockerfile文件,并在文件中输入以下内容:

#使用sbr/jre8:1.0.0作为基础镜像
FROM sbr/jre8:1.0.0

#编写人/维护人
MAINTAINER caochuanhong#sbr-info.com

#java应用文件操作
COPY ms-auth-2.1.2051-SNAPSHOT.jar /ms-auth-2.1.2051-SNAPSHOT.jar

#声明端口
EXPOSE 9003

#容器启动后,执行的命令
ENTRYPOINT ["java", "-jar", "/ms-auth-2.1.2051-SNAPSHOT.jar"]

构建微服务项目镜像

将命令行定位到app目录下,执行以下命令:

docker build -t sbr/app:1.0.0 .

说明:

  • -t:给要构建的镜像定义一个名称
  • . 这个.代表着,让docker去读取当前目录下的Dockerfile文件来构建镜像


    11.png

    12.png

微服务项目配置文件与启动

在启动微服务项目前,需要先看一下项目中的配置文件,有几点需要注意
在项目源码的resource目录下的application.yml文件中


13.png

    spring boot类型项目中的配置项,可以通过修改环境变量的方式来赋值,spring会优先读取环境变量中的配置项和配置项目值

    在docker中,访问127.0.0.1是访问的容器内部,而不是宿主机,所以,需要一种灵活的方式能够动态的配置连接信息,而通过简短的环境变量的形式来配置连接参数是一个好的选择。

    无论是通过配置宿主机上的环境变量还是在启动容器的时候,来动态为容器指定环境变量的值,都可以将配置的值映射到容器内部的应用服务的配置中,从而避免连接属性写死的情况。更多的关于spring boot项目配置的信息,请参考如下:http://www.cnblogs.com/softidea/p/5759180.html

    所以,在启动微服务项目的时候,附带上上图中配置的项,就可以正确的连接到mysql和redis服务中。

首先,先获取本机的IP地址,然后将本机的IP地址通过环境变量的方式配置到容器的启动命令中,比如我的IP是192.168.6.56

通过以下命令来启动微服务的应用:

docker run -p 9003:9003 -e DB_SERVER=192.168.6.56 -e DB_REDIS_HOST=192.168.6.56 --name sbr-app 5b1df7a17cff

如果redis的连接密码和项目中配置的不一致时,可以通过 -e DB_REDIS_PWD=xxx来动态修改密码。

该命令会在终端输出启动日志,如果想让docker后台启动该容器,可以在命令中添加-d参数

当容器启动后,就可以通过rest连接工具正常访问该项目提供的服务了,访问情况如下图所示:


15.png

使用Docker compose编排服务

    上一章中,已经介绍了使用docker手动的方式来介绍微服务在docker环境下的部署。但是,这样去操作docker是很原始的,通过手动的一个一个的去启动服务容器,既费时又费力。

    Docker 也提供了更强大的工具 Compose 来管理容器。

    Docker Compose是一个用来定义和运行复杂应用的Docker工具。一个使用Docker容器的应用,通常由多个容器组成。使用Docker Compose不再需要使用shell脚本来启动容器。

    Compose 通过一个配置文件来管理多个Docker容器,在配置文件中,所有的容器通过services来定义,然后使用docker-compose脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器,非常适合组合使用多个容器进行开发的场景。

    更多关于docker compose的内容,请参考Docker操作指南中的docker compose部分。

编写compose配置文件来管理多个容器

    通过Docker操作指南中的docker compose部分我们知道,compose可以通过Dockerfile文件来创建镜像和容器。

    那么下面,我们通过docker compose的方式来管理我们的镜像和容器.

  创建一个docker-compose.yml配置文件,该文件与jre,mysql,redis,app目录是同级的。并将以下内容复制到docker-compose.yml文件中。

#使用的compose版本
version: '3'

#compose关键字,定义services
services:

 #service的名称 sbr_redis
 sbr_redis: 
  #service中容器的名称
  container_name: sbr_redis
  #使用当前目录下的redis目录下的Dockerfile来创建镜像
  build: ./redis
  #当前服务向外暴漏的端口
  ports: 
   - "6379:6379"
  #指定创建redis容器后,设置的密码
  command: 
   - "--requirepass Admin@123"
   
 #service的名称 sbr_mysql
 sbr_mysql: 
  #service中容器的名称
  container_name: sbr_mysql
  #使用当前目录下的mysql目录下的Dockerfile来创建镜像
  build: ./mysql 
  #当前服务向外暴漏的端口
  ports: 
   - "3306:3306"
   
 #service的名称 sbr_user_auth
 sbr_user_auth: 
  #service中容器的名称
  container_name: sbr_app 
  #使用当前目录下的app目录下的Dockerfile来创建镜像
  build: ./app
  #当前服务向外暴漏的端口
  ports: 
   - "9003:9003"
  #当前容器使用的环境变量
  environment:
   - DB_SERVER=sbr_mysql
   - DB_REDIS_HOST=sbr_redis
  #当前服务依赖depends_on配置的服务,docker compose会优先启动依赖的服务
  depends_on:
   - sbr_mysql
   - sbr_redis

    默认情况下,Compose 会为你的应用程序设置一个 网络。服务的每个容器都加入默认网络,并且该网络上的其他容器都可以访问它们,并且可以通过与容器名称相同的主机名来发现它们。所以,在设置数据库连接和redis的连接时,没有设置具体的IP地址,而是设置的服务名,这样,docker compose会自动去访问对应的服务。

输入以下命令来构建以上配置的所有镜像

docker-compose build

该命令会构建镜像,或者输入以下命令,构建镜像并启动容器

docker-compose up --build

该命令会在启动前就行构建镜像,构建完成后,再启动容器,如果不加参数 -d 的话,会在终端输入构建以及启动日志,截图如图所示:


![15.png](https://upload-images.jianshu.io/upload_images/15499641-82bcd0c80102ee9d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

使用rest连接工具,来验证服务是否已经成功。

至此,微服务项目通过被docker compose管理的使用场景已经整理完毕:

<font color=red>
请注意:使用compose进行启动到容器,在日志打印时,微服务项目会报连不到数据库到错误,这是正常到,因为,此时,mysql容器正在启动,而没有启动完毕,所以导致无法连接到数据库,而hibernate中有重连机制,在mysql正常启动后,就可以连接上了。关于depend_on到设置,compose只能检测到容器到启动状态,若容器启动,则compose认为这已经是成功启动了,所以,关于这一点报错到问题,请大家知悉,这是正常到。当然,也可以通过其他到方式来处理这个问题。
</font>

总结

docker 的使用过程,它分为镜像构建与容器启动。

镜像构建:即创建一个镜像,它包含安装运行所需的环境、程序代码等。这个创建过程就是使用 dockerfile 来完成的。

容器启动:容器最终运行起来是通过拉取构建好的镜像,通过一系列运行指令(如端口映射、外部数据挂载、环境变量等)来启动服务的。针对单个容器,这可以通过 docker run 来运行。

而如果涉及多个容器的运行(如服务编排)就可以通过 docker-compose 来实现,它可以轻松的将多个容器作为 service 来运行(当然也可仅运行其中的某个),并且提供了 scale (服务扩容) 的功能。

最后,docker,Dockerfile,compose的使用情况:

  • Dockerfile: 构建镜像

  • docker run: 启动容器

  • docker-compose: 启动服务(包含多个容器)

以上所有章节内容为微服务项目在docker环境下的使用情况,各位在实践过程中,如果出现了什么问题,可随时与我联系。

附录

<a name=jre>制作微服务所需的jre基础镜像</a>

镜像选择

    在制作镜像、Docker创建容器时,基础镜像通常选择Ubuntu或Centos,不管哪个镜像的大小都在100MB以上。

    我们必须要知道的一个事情是,镜像也是要占用存储空间的。那么,设计或者使用一个磁盘占用较小的镜像,是一个比较好的选择。
通过对比和资料查找后,推荐使用Alpine Linux 作为jre的基础镜像。

    Alpine Linux 是一个轻量级的 Linux 发行版,基于 musl libc 及 busybox。其关注于性能及安全性,追求小(Small)、简单(Simple)及安全(Secure)。其常被应用于构建 Docker 等容器。

    在使用前,我们应该知道java是需要glibc的,所以基础镜像使用的是alpine-glibc而非alpine,alpine-glibc大概是11.1M。

jre基础镜像

#解压
tar xvcf jre1.8.0_191.tar.gz
#进入目录
cd jre1.8.0_191/
#删除文本文件
rm -rf COPYRIGHT LICENSE README release THIRDPARTYLICENSEREADME-JAVAFX.txtTHIRDPARTYLICENSEREADME.txt Welcome.html
#删除其他无用文件
rm -rf     lib/plugin.jar \
           lib/ext/jfxrt.jar \
           bin/javaws \
           lib/javaws.jar \
           lib/desktop \
           plugin \
           lib/deploy* \
           lib/*javafx* \
           lib/*jfx* \
           lib/amd64/libdecora_sse.so \
           lib/amd64/libprism_*.so \
           lib/amd64/libfxplugins.so \
           lib/amd64/libglass.so \
           lib/amd64/libgstreamer-lite.so \
           lib/amd64/libjavafx*.so \
           lib/amd64/libjfx*.so
  • jre重新打包
tar -zcvf jre1.8.0_191.tar.gz jre1.8.0_191

基础镜像的Dockerfile的编写

    新建一个jre目录,将刚才处理过的jre1.8.0_191.tar.gz包放入到jre目录中。并在jre目录中,新建一个Dockerfile文件,将以下内容复制到Dockerfile文件中

#使用alpine-glibc作为基础镜像
FROM docker.io/jeanblanchard/alpine-glibc

#编写人/维护人,这里可以写自己的信息
MAINTAINER caochuanhong@sbr-info.com

#定义jre安装到路径,可以在run 指令中,附带 -e JREDIR=/x/x/x来配置jre的安装路径
ENV JREDIR /opt/sbr/jre

#添加gz包到镜像内,gz包会自动解压
ADD jre1.8.0_191.tar.gz ${JREDIR}

#设置环境变量
ENV JAVA_HOME ${JREDIR}/jre1.8.0_191
ENV PATH ${PATH}:${JAVA_HOME}/bin

构建jre基础镜像

将命令行定位到jre目录中,输入以下命令来构建我们自己的镜像

输入

docker image ls

查看当前镜像列表,如图所示:


1.png

输入


docker build -t sbr/jre8 .

来开始进行jre基础镜像的构建

说明:

  • -t:给要构建的镜像定义一个名称,也可以附带镜像的版本号,比如:sbr/jre8:1.0.0
  • . 这个.代表着,让docker去读取当前目录下的Dockerfile文件来构建镜像
2.jpg

此时,jre基础镜像已经制作完成,我们可以通过该镜像,创建一个容器,进入内容内部执行java -version来验证。

首先,我们先复制该镜像的id:b3adba0789cd
然后,输入以下内容,创建并进入容器内部:

docker run -it --name myjre8 b3adba0789cd /bin/sh

说明:

  • -i: 以交互模式运行容器,通常与 -t 同时使用;
  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
  • --name: 为创建的容器设置一个名称
  • /bin/sh: 容器启动后,执行的脚本

最终效果如图所示:


3.png

通过输入exit来退出容器

至此,jre基础镜像的制作已经完毕,

推荐阅读更多精彩内容

  • 1.Compose介绍 Docker Compose是一个用来定义和运行复杂应用的Docker工具。一个使用Doc...
    渝味阅读 5,494评论 0 2
  • 成品 找到想要的图片,照着大致用铅笔画出 之后用水性笔等黑色笔描黑,看个人情况,上色或者不上色都可以 生活的改变总...
    覃格尔阅读 115评论 2 2
  • 五月花开季,龙舟蓄势征。湘灵斑叶落,九鼎帝王横。海阔其人淡,天高旧梦成。三闾泉路笑,霸主楚庄峥。
    浮零先生阅读 147评论 0 14