快捷搜索:

您的位置:澳门新葡4473网站 > 项目 > Docker 系列七(Duubo 微服务部署实践).

Docker 系列七(Duubo 微服务部署实践).

发布时间:2019-11-02 07:14编辑:项目浏览(148)

    一、前言

        之前我们公司部署服务,就是大家都懂的那一套(安装JDK、Tomcat —> 编译好文件或者打war包上传 —> 启动Tomcat),这种部署方式一直持续了很久,带来的问题也很多:

    1、繁重的发布任务。微服务一多,就要每个服务都要重启一遍,而且要是集群的话,那要启动的服务就更多了。

    2、环境迁移报错。经常发生的一件事,同样的一套代码,这台服务器上就是能跑起来,换个服务器就是报错了。

    3、士气低落。小公司没有正经的运维,都是让开发兼并着做这方面的工作,然后负责这块的同事怨言很多(因为这种发布部署实在太无趣了)。

        所以领导决定引起 Docker 作为我们的部署方式,一来可以很好的解决目前项目部署存在的问题,二来为项目注入新鲜血液。

        从上个月15号开始接触 Docker,到现在把我们系统的微服务架构初步搭建好,折腾了好久,踩了很多坑。纪念一下小成就,写了这篇博客。为了避免涉嫌泄露公司机密,就小而全的做一些简单介绍哈,以下面这张最小微服务架构图为例,部署一套 Dubbo 微服务。

    图片 1

    热部署

    pom.xml文件中添加spring-boot-devtools依赖即可实现页面和代码的热部署。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
    

    二、服务镜像打包

    常规部署

         1、Tomcat 基础环境搭建

        我们系统的每个微服务都部署运行在 Tomcat 上(听说这种方式很不好,对于一些不是web工程的,没必要搭建成 web 服务,增加复杂性,也浪费系统资源),所以我的想法是:先搭建一套 Tomcat 环境镜像,然后每个微服务都基于这个环境镜像去构建。所以写了一个 tomcat-env 的镜像,思路如下:

        -- 基于 JDK 的 Tomcat 容器(主要参考官网 Tomcat 镜像的 Dockerfile)。

        -- 在上下文目录存放项目编译文件,并重命名为 ROOT(不放 war 包的原因是考虑调试的时候方便,不用改一个文件,就打个war包)。

        -- 删除原本 Tomcat 容器 webapps 目录下的 ROOT 文件,并将上下文目录中项目的 ROOT 文件夹上传到容器 webapps 目录下。

        -- 启动服务。

    图片 2图片 3

    FROM openjdk:8-jre
    
    ENV CATALINA_HOME /usr/local/tomcat
    ENV PATH $CATALINA_HOME/bin:$PATH
    RUN mkdir -p "$CATALINA_HOME"
    WORKDIR $CATALINA_HOME
    
    # let "Tomcat Native" live somewhere isolated
    ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
    ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR
    
    # runtime dependencies for Tomcat Native Libraries
    # Tomcat Native 1.2+ requires a newer version of OpenSSL than debian:jessie has available
    # > checking OpenSSL library version >= 1.0.2...
    # > configure: error: Your version of OpenSSL is not compatible with this version of tcnative
    # see http://tomcat.10.x6.nabble.com/VOTE-Release-Apache-Tomcat-8-0-32-tp5046007p5046024.html (and following discussion)
    # and https://github.com/docker-library/tomcat/pull/31
    ENV OPENSSL_VERSION 1.1.0f-3+deb9u2
    RUN set -ex; 
        currentVersion="$(dpkg-query --show --showformat '${Version}n' openssl)"; 
        if dpkg --compare-versions "$currentVersion" '<<' "$OPENSSL_VERSION"; then 
            if ! grep -q stretch /etc/apt/sources.list; then 
    # only add stretch if we're not already building from within stretch
                { 
                    echo 'deb http://deb.debian.org/debian stretch main'; 
                    echo 'deb http://security.debian.org stretch/updates main'; 
                    echo 'deb http://deb.debian.org/debian stretch-updates main'; 
                } > /etc/apt/sources.list.d/stretch.list; 
                { 
    # add a negative "Pin-Priority" so that we never ever get packages from stretch unless we explicitly request them
                    echo 'Package: *'; 
                    echo 'Pin: release n=stretch*'; 
                    echo 'Pin-Priority: -10'; 
                    echo; 
    # ... except OpenSSL, which is the reason we're here
                    echo 'Package: openssl libssl*'; 
                    echo "Pin: version $OPENSSL_VERSION"; 
                    echo 'Pin-Priority: 990'; 
                } > /etc/apt/preferences.d/stretch-openssl; 
            fi; 
            apt-get update; 
            apt-get install -y --no-install-recommends openssl="$OPENSSL_VERSION"; 
            rm -rf /var/lib/apt/lists/*; 
        fi
    
    RUN apt-get update && apt-get install -y --no-install-recommends 
            libapr1 
        && rm -rf /var/lib/apt/lists/*
    
    # see https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/KEYS
    # see also "update.sh" (https://github.com/docker-library/tomcat/blob/master/update.sh)
    ENV GPG_KEYS 05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 61B832AC2F1C5A90F0F9B00A1C506407564C17A3 713DA88BE50911535FE716F5208B0AB1D63011C7 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23
    
    ENV TOMCAT_MAJOR 8
    ENV TOMCAT_VERSION 8.0.53
    ENV TOMCAT_SHA512 cd8a4e48a629a2f2bb4ce6b101ebcce41da52b506064396ec1b2915c0b0d8d82123091242f2929a649bcd8b65ecf6cd1ab9c7d90ac0e261821097ab6fbe22df9
    
    ENV TOMCAT_TGZ_URLS 
    # https://issues.apache.org/jira/browse/INFRA-8753?focusedCommentId=14735394#comment-14735394
        https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz 
    # if the version is outdated, we might have to pull from the dist/archive :/
        https://www-us.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz 
        https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz 
        https://archive.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz
    
    ENV TOMCAT_ASC_URLS 
        https://www.apache.org/dyn/closer.cgi?action=download&filename=tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc 
    # not all the mirrors actually carry the .asc files :'(
        https://www-us.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc 
        https://www.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc 
        https://archive.apache.org/dist/tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc
    
    RUN set -eux; 
        
        savedAptMark="$(apt-mark showmanual)"; 
        apt-get update; 
        
        apt-get install -y --no-install-recommends gnupg dirmngr; 
        
        export GNUPGHOME="$(mktemp -d)"; 
        for key in $GPG_KEYS; do 
            gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; 
        done; 
        
        apt-get install -y --no-install-recommends wget ca-certificates; 
        
        success=; 
        for url in $TOMCAT_TGZ_URLS; do 
            if wget -O tomcat.tar.gz "$url"; then 
                success=1; 
                break; 
            fi; 
        done; 
        [ -n "$success" ]; 
        
        echo "$TOMCAT_SHA512 *tomcat.tar.gz" | sha512sum -c -; 
        
        success=; 
        for url in $TOMCAT_ASC_URLS; do 
            if wget -O tomcat.tar.gz.asc "$url"; then 
                success=1; 
                break; 
            fi; 
        done; 
        [ -n "$success" ]; 
        
        gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz; 
        tar -xvf tomcat.tar.gz --strip-components=1; 
        rm bin/*.bat; 
        rm tomcat.tar.gz*; 
        command -v gpgconf && gpgconf --kill all || :; 
        rm -rf "$GNUPGHOME"; 
        
        nativeBuildDir="$(mktemp -d)"; 
        tar -xvf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1; 
        apt-get install -y --no-install-recommends 
            dpkg-dev 
            gcc 
            libapr1-dev 
            libssl-dev 
            make 
            "openjdk-${JAVA_VERSION%%[.~bu-]*}-jdk=$JAVA_DEBIAN_VERSION" 
        ; 
        ( 
            export CATALINA_HOME="$PWD"; 
            cd "$nativeBuildDir/native"; 
            gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; 
            ./configure 
                --build="$gnuArch" 
                --libdir="$TOMCAT_NATIVE_LIBDIR" 
                --prefix="$CATALINA_HOME" 
                --with-apr="$(which apr-1-config)" 
                --with-java-home="$(docker-java-home)" 
                --with-ssl=yes; 
            make -j "$(nproc)"; 
            make install; 
        ); 
        rm -rf "$nativeBuildDir"; 
        rm bin/tomcat-native.tar.gz; 
        
    # reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
        apt-mark auto '.*' > /dev/null; 
        [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; 
        apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; 
        rm -rf /var/lib/apt/lists/*; 
        
    # sh removes env vars it doesn't support (ones with periods)
    # https://github.com/docker-library/tomcat/issues/77
        find ./bin/ -name '*.sh' -exec sed -ri 's|^#!/bin/sh$|#!/usr/bin/env bash|' '{}' +
    
    # verify Tomcat Native is working properly
    RUN set -e 
        && nativeLines="$(catalina.sh configtest 2>&1)" 
        && nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')" 
        && nativeLines="$(echo "$nativeLines" | sort -u)" 
        && if ! echo "$nativeLines" | grep 'INFO: Loaded APR based Apache Tomcat Native library' >&2; then 
            echo >&2 "$nativeLines"; 
            exit 1; 
        fi
    
    EXPOSE 8080
    RUN rm -rf /usr/local/tomcat/webapps/ROOT/
    ONBUILD COPY ROOT /usr/local/tomcat/webapps/ROOT/
    ONBUILD ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]
    

    tomcat-env

    看起来很复杂,不要被吓到,其实都是抄的官网 Tomcat 镜像的Dockerfile,然后改动了一点,主要是后面三句:删除容器 ROOT 文件夹,拷贝上下文目录的 ROOT 文件夹到 wenapps 目录下,重启服务。

    RUN rm -rf /usr/local/tomcat/webapps/ROOT/
    ONBUILD COPY ROOT /usr/local/tomcat/webapps/ROOT/
    ONBUILD ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]
    

    tips:1、ONBUILD 命令本次镜像不会被执行,只有以这个镜像为基础镜像的时候才会被执行。

              2、上下文目录指的是 Dockerfile 文件所在的目录。

              3、该镜像已上传到 DockerHub 上:https://hub.docker.com/r/jmcui/tomcat-env/

    jar

    • 打包
    mvn package
    
    • 运行
    java -jar xxx.jar
    
    • war 转 jar

      • pom.xml文件中将<packaging>war</packaging>改为<packaging>jar</packaging>
      • 去掉ServletInitializer类
      • 去掉如下依赖,恢复默认内嵌Tomcat依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        
    • 注册Linux服务

      • 修改spring-boot-maven-plugin配置

        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <executable>true</executable>
                    </configuration>
                <plugin>
            </plugins>
        </build>
        
      • 使用mvn package打包

      • 使用init.d或systemd注册服务

        • init.d部署
          注册服务

          sudo ln -s /var/apps/xxx.jar /etc/init.d/xxx
          

          启动服务

          service xxx start
          

          停止服务

          service xxx stop
          

          服务状态

          service xxx status
          

          开机启动

          chkconfig xxx on
          

          日志存放在/var/log/xxx.log。

        • systemd部署
          注册服务
          在/etc/systemd/system/目录下新建文件xxx.service,xxx.service内容如下:

          [Unit]
          Description=xxx
          After=syslog.target
          
          [Service]
          ExecStart= /usr/bin/java -jar /var/apps/xxx.jar
          
          [Install]
          WantedBy=multi-user.target
          

          启动服务

          systemctl start xxx
          
          systemctl start xxx.service
          

          停止服务

          systemctl stop xxx
          
          systemctl stop xxx.service
          

          服务状态

          systemctl status xxx
          
          systemctl status xxx.service
          

          开机启动

          systemctl enable xxx
          
          systemctl enable xxx.service
          

          项目日志

          journalctl -u xxx
          
          journalctl -u xxx.service
          

         2、微服务镜像打包

        有了基础环境镜像 tomcat-env,那么打包一个服务镜像就是一件再简单不过的事情了:

    图片 4

    FROM tomcat-env:1.0
    

        没错,就是这么简单,因为我们把所有的工作都放在 tomcat-env 中了,其实就是那个 ONBUILD 命令的效果啦~~ 

    war

    • 打包
    mvn package
    
    • 运行
      将war包丢到支持war文件的Servlet容器执行。
    • jar 转 war

      • pom.xml文件中将<packaging>jar</packaging>改为<packaging>war</packaging>
      • 增加ServletInitializer类

        import org.springframework.boot.builder.SpringApplicationBuilder;
        import org.springframework.boot.context.web.SpringBootServletInitializer;
        public class ServletInitializer extends SpringBootServletInitializer {
            @Override
            protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
                return application.source(XxxApplication.class)
            }
        }
        
      • 增加如下依赖,覆盖默认内嵌Tomcat依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        

    三、编排文件 docker-compose.yml

        微服务项目要部署起来,主要是靠 docker-compose.yml 文件进行编排,规定服务之间的关联以及先后启动顺序,然后把几十个零散的微服务当成一个整体来统一管理。

        首先,困扰我的是网络问题。做过开发的都知道,要在项目中指定(Spring 在 applicationContext.xml)数据库地址和 Zookeeper 地址,那么我怎么知道容器的 ip 地址是多少呢?先来了解下 Docker 的网络模式?

        Docker 的默认网络配置是 "bridge",当 Docker 启动时,会自动在主机上创建一个 docker0 虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。Docker 会随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一个地址给 docker0 接口,它会在挂载到它的网口之间进行转发。当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口。这对接口一端在容器内,即 eth0;另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头(例如 vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。

         也就是说,每次容器启动以后的 ip 地址是不固定的,这该怎么办呢?当然可以写死 IP 地址,规定局域网网段,给每个服务编排 IP 地址;当然也可以把network_mode="host",统一用宿主机的网络地址。当然!这些都不是最好的办法:

    version: '3.7'
    #服务列表
    services:
      #基础组件 zookeeper  
      zookeeper:
        image: zookeeper
        restart: always
        ports:
          - 4181:2181
      #基础组件 MySQL
      db:
        image: mysql:5.7.17
        command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --init-connect='SET NAMES utf8mb4;'
        ports:
         - "3636:3306"
        volumes:
         - /var/mysqldb:/var/lib/mysql
         - /docker/mysql/my.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
        restart: always
        environment:
          MYSQL_ROOT_PASSWORD: password
      #消费者服务1 admin
      admin:
        image: "admin:2.3.1"
        ports:
         - "7575:8080"
        depends_on:
         - zookeeper
        restart: always
        environment:
          zookeeper.host: zookeeper://zookeeper:2181
      #提供者服务1 system
      system:
        image: "system:2.3.1"
        depends_on:
         - db
         - zookeeper
        restart: always
        environment:
          zookeeper.host: zookeeper://zookeeper:2181
          mysql.address: db:3306
    

        看到了吗?IP 地址直接由 服务名 指定就可以了。另外, Docker 中设置的环境变量,竟然能被 applicationContext.xml 中读取,我也是蛮诧异的!(在代码和 Docker 中都配置了mysql.address 的话,以 Docker 中设置的生效)。

        然后 docker-compose up -d 启动微服务项目就可以了~~

        容器部署的一个原则:尽量不要在容器内部做文件的修改,要修改的内容用数据卷的方式映射到宿主机上,比如上面的MySQL配置文件和数据仓库。

    图片 5

        在 Docker 上部署 MySQL 遇到了几个问题,简单罗列下:

    1、Navicat 连接的时候: Client does not support authentication protocol requested by server ?

    解决:进入 MySQL 容器,运行

    ALTER user 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
    

    2、Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre 的问题?

    原因:MySQL 5.7.5及以上功能依赖检测功能。如果启用了ONLY_FULL_GROUP_BY SQL模式(默认情况下),MySQL将拒绝选择列表,HAVING条件或ORDER BY列表的查询引用在GROUP BY子句中既未命名的非集合列,也不在功能上依赖于它们。

    解决:在MySQL的配置文件中加上:

    sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
    

    3、MySQL 连接参数useSSL=true 和 useSSL=false 的区别?

        建议不要在没有服务器身份验证的情况下建立SSL连接(同一个 Docker-compose 中是内网环境)。根据 MySQL 5.5.45 +,5.6.26 +和5.7.6+ 要求如果未设置显式选项,则必须默认建立SSL连接。为了符合不使用SSL的现有应用程序。您需要通过设置useSSL = false显式禁用SSL,或者设置useSSL = true并为服务器证书验证提供信任库。

    云部署

    四、结语

        总算是把一个微服务项目部署运行起来了,几乎是用了最少的 Docker-compose 模板文件,所以还是有很多地方可以完善的,比如说 MySQL 密码没有加密处理、服务没有做健康检查、集群方面还没怎么考虑(用 Docker Swarm 实现)等等......路漫漫其修远兮,吾将上下而求索。共勉!

    Docker

    使用Dockerfile编译Docker镜像。

    Dockerfile指令

    • FROM
      指明当前镜像继承的基镜像,编译当前镜像时会自动下载基镜像。

      FROM java:8
      
    • MAINTAINER
      指明当前镜像的作者。

      MAINTAINER linliangsheng
      
    • RUN
      当前镜像上执行Linux命令并形成一个新的层,编译时(build)动作。

      RUN /bin/bash -c "echo hello"
      
      RUN ["/bin/bash", "-c", "echo hello"]
      
    • CMD
      启动镜像容器时的默认行为,一个Dockerfile只能有一个CMD指令,可在运行镜像时使用参数覆盖,运行时(run)动作。

      CMD echo "hello"
      

      参数覆盖写法:

      docker run -d image_name echo "docker-hello"
      
    • EXPOSE
      指明镜像运行时的容器必需监听指定的端口。

      EXPOSE 8080
      
    • ENV
      设置环境变量。

      ENV name=linliangsheng
      
      ENV name linliangsheng
      
    • ADD
      从当前工作目录复制文件到镜像目录。

      ADD xxx.jar app.jar
      
    • ENTRYPOINT
      让容器像可执行程序一样运行,镜像运行时可接收参数,运行时(run)动作。

      ENTRYPOINT ["java"]
      

      参数接收写法:

      docker run -d image_name "-jar app.jar"
      

    Docker安装

    • 安装Docker

      yum install docker
      
    • 启动Docker

      systemctl start docker
      
    • 开机自启动

      systemctl enable docker
      

    Docker实践

    Spring Boot实践

    在xxx.jar包同级目录建立Dockerfile文件,Dockerfile文件内容如下:

    FROM java:8
    MAINTAINER linliangsheng
    ADD xxx.jar app.jar
    EXPOSE 8080
    ENTRYPOINT ["java", "-jar", "/app.jar"]
    

    编译镜像:

    docker build -t wisely/xxx .
    

    运行镜像:

    docker run -d --name xxx -p 8080:8080 wisely/xxx
    

    Spring Cloud实践

    1. 编写runboot.sh脚本
      位于src/main/docker下:

      sleep 10
      java -Djava.security.egd=file:/dev/./urandom -jar /app/app.jar
      

      根据启动顺序调整sleep时间

    2. 编写Dockerfile
      位于src/main/docker下:

      FROM java:8
      VOLUME /tmp
      RUN mkdir /app
      ADD xxx.jar /app/app.jar
      ADD runboot.sh /app/
      RUN bash -c 'touch /app/app.jar'
      WORKDIR /app
      RUN chmod a+x runboot.sh
      EXPOSE 8888
      CMD /app/runboot.sh
      

      不同的微服务只需修改

      ADD xxx.jar /app/app.jar
      EXPOSE 8888
      
    3. Docker插件
      在pom.xml中增加docker-maven-plugin插件

      <build>
          <plugins>
              <plugin>
                  <groupId>com.spotify</groupId>
                  <artifactId>docker-maven-plugin</artifactId>
                  <configuration>
                      <imageName>${project.name}:${project.version}</imageName>
                      <dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>
                      <skipDockerBuild>false</skipDockerBuild>
                      <resources>
                          <resource>
                              <directory>${project.build.directory}</directory>
                              <include>${project.build.finalName}.jar</include>
                          </resource>
                      </resources>
                  </configuration>
              </plugin>
          </plugins>
      </build>
      
    4. 编译镜像
      docker-maven-plugin默认将Docker编译到localhost,如果是远程Linux服务器,需要配置环境变量DOCKER_HOST,变量值tcp://IP地址:端口号
      执行mvn命令进行镜像编译:

      mvn clean package docker:build -DskipTests
      
    5. Docker Compose
      Docker Compose是用来定义和运行多容器应用的工具,使用一个docker-compose.yml来描述多容器定义,使用docker-compose up -d运行整个应用,-d表示后台运行。
      docker-compose.yml参考内容:

      postgresdb:
        image: busybox
        volumes:
          - /var/lib/postgresql/data
      postgres:
        name: postgres
        image: postgres
        hostname: postgres
        volumes_from:
          - postgresdb
        environment:
          - POSTGRES_USER=postgres
          - POSTGRES_PASSWORD=postgres
      discovery:
        name: discovery
        image: "discovery:1.0.0-SNAPSHOT"
        hostname: discovery
        ports:
          - "8761:8761"
      config:
        name: config
        image: "config:1.0.0-SNAPSHOT"
        hostname: config
        links:
          - discovery
        environment:
          - EUREKA_HOST: discovery
          - EUREKA_PORT: 8761
        ports:
          - "8888:8888"
      person:
        name: person
        image: "person:1.0.0-SNAPSHOT"
        hostname: person
        links:
          - discovery
          - config
          - postgres
        environment:
          - EUREKA_HOST: discovery
          - EUREKA_PORT: 8761
          - SPRING_PROFILES_ACTIVE: docker
        ports:
          - "8082:8082"
      some:
        name: some
        image: "some:1.0.0-SNAPSHOT"
        hostname: some
        links:
          - discovery
          - config
        environment:
          - EUREKA_HOST: discovery
          - EUREKA_PORT: 8761
          - SPRING_PROFILES_ACTIVE: docker
        ports:
          - "8083:8083"
      ui:
        name: ui
        image: "ui:1.0.0-SNAPSHOT"
        hostname: ui
        links:
          - discovery
          - config
          - person
          - some
        environment:
          - EUREKA_HOST: discovery
          - EUREKA_PORT: 8761
          - SPRING_PROFILES_ACTIVE: docker
        ports:
          - "80:80"
      monitor:
        name: monitor
        image: "monitor:1.0.0-SNAPSHOT"
        hostname: monitor
        links:
          - discovery
          - config
          - person
          - some
          - ui
        environment:
          - EUREKA_HOST: discovery
          - EUREKA_PORT: 8761
          - SPRING_PROFILES_ACTIVE: docker
        ports:
          - "8989:8989"
      

    FAQ

    1. 编译打包报错I/O exception (java.io.IOException) caught when processing request to {}->unix://localhost:80: Permission denied
      需要配置DOCKER_HOST环境变量,Ubuntu16.04LTS中环境变量配置是修改~/.bashrc文件,增加export DOCKER_HOST=tcp://127.0.0.1:5555,使配置的环境变量立即生效source ~/.bashrc。同时,需要修改Docker后台进程监听5555端口,编辑/etc/default/docker,增加DOCKER_OPTS="-H 0.0.0.0:5555",然后service docker restart重启Docker。
    2. 编译打包报错Exception caught: Get https://registry-1.docker.io/v2/: net/http: TLS handshake timeout
      多次编译打包就可以解决。
      Tip:
      查看本地镜像命令:docker images
      查看当前容器状态:docker ps

    参考资料

    Java EE开发的颠覆者-Spring Boot实战.汪云飞.407-424,478-484

    本文由澳门新葡4473网站发布于项目,转载请注明出处:Docker 系列七(Duubo 微服务部署实践).

    关键词: