微服务的Docker发布和部署


本文主要记录微服务通过Maven插件实现生成镜像,并发布到本地仓库和远程的中央仓库。在此之前需要安装好相关的环境,如本地docker服务,docker桌面工具Docker Desktop for Windows (官网上也有Docker Desktop for Mac和Docker Desktop for Linux,这里以Windows为例),然后再准备一个SpringBoot微服务就行了。下面开始造起来

注册DockerHub

首先需要注册一个DockerHub账号,DockerHub官网地址。DockerHub是一个和GitHub功能类似的网站,只不过托管的文件不一样,GitHub托管代码,而DockerHub托管镜像。账号注册好了以后我们需要创建一个镜像仓库地址,这和在GitHub上创建代码仓库地址一样。

  1. 在dockerhub主要点击Repositories进入到仓库页面,然后点击右上角的Create Repository创建仓库

  2. 然后填写仓库名,描述,公有或是私有仓库

  3. 创建好了后,来到仓库页面

到这里DockerHub的工作就完成了,我创建了一个spring-boot-demo的镜像仓库,里面什么也没有,只是一个空仓库。接下来要做的就是在本地生成镜像,并把镜像push到这个仓库中

本地运行Docker

本地的windows安装好docker后,打开Docker Desktop如下图,我本地是发布了一些镜像所以这里能看到这些镜像,如果是第一次安装,这里就是空的

在设置的地方可以修改docker的一些配置,比如Cpu个数,内存大小,磁盘大小等。

Docker Desktop中还集成了kubernetes,我们可以选择启用一个单实例的k8s集群来体验容器编排的功能

本地生成镜像

前面准备工作都做完了以后,来到重头戏,实现本地打包时生成镜像并发布到本地的docker服务中,并且实现镜像发布到远程的dockerhub仓库中。需要用到一个docker的插件dockerfile-maven-plugin

默认情况下,该插件通过访问localhost:2375来连接本地docker,可以通过设置DOCKER_HOST 环境变量来连接docker,即DOCKER_HOST=tcp://<host>:2375 。如果没有设置 DOCKER_HOST 环境变量,也可以命令行显示指定 DOCKER_HOST 来执行,如我本机指定 DOCKER_HOST:DOCKER_HOST=unix:///var/run/docker.sock mvn clean install docker:build

直接上maven配置,下面这个配置是最终的配置,接下来会解释每个配置项的作用

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <name>spring-boot-demo</name>
    <artifactId>spring-boot-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.resource.version>3.1.0</maven.resource.version>
        <java.version>1.8</java.version>
        <docker.skip.build>build</docker.skip.build>
        <docker.image.prefix>lushunjian</docker.image.prefix>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

    </dependencies>

    <build>
        <plugins>
            <!--编译插件-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <!-- docker的maven插件,官网:https://github.com/spotify/docker-maven-plugin -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.4.12</version>

                <!--插件绑定到phase, 在install阶段生成镜像-->
                <executions>
                    <execution>
                        <phase>install</phase>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>

                <configuration>
                    <!--配置变量,包括是否build、imageName、imageTag,非常灵活-->
                   <!-- <skipDocker>${docker.skip.build}</skipDocker>-->

                    <!-- 注意imageName一定要是符合正则[a-z0-9-_.]的,否则构建不会成功 -->
                    <!-- 详见:https://github.com/spotify/docker-maven-plugin    Invalid repository name ... only [a-z0-9-_.] are allowed-->
                    <!-- 如果要将docker镜像push到DockerHub上去的话,这边的路径要和repo路径一致 -->
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <!-- 每次生成两个tag版本,一个本身的版本号,另一个最新的latest版本 -->
                    <imageTags>
                        <imageTag>${project.version}</imageTag>
                        <imageTag>latest</imageTag>
                    </imageTags>
                    <!-- 指定Dockerfile所在的路径 -->
                    <dockerDirectory>${basedir}/src/main/resources</dockerDirectory>
                    <!--<baseImage>java</baseImage>-->
                    <!--<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>-->
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>

                    <!--push到私有的hub-->
                    <serverId>docker-hub</serverId>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Dockerfile配置,放在SpringBoot的resources目录下

FROM java:8
VOLUME /tmp
ADD spring-boot-demo-1.0-SNAPSHOT.jar app.jar
RUN bash -c 'touch /app.jar'
EXPOSE 8090
ENTRYPOINT ["java","-jar","/app.jar"]

注意这里的EXPOSE表示暴露的端口,这里的端口不是对外映射的端口,而是容器暴露的端口,这个端口要和微服务进程的端口保持一致,微服务的application.yml配置如下

server:
  port: 8090

插件下载好后,会有几个插件提供的命令

docker:build是编译生成docker镜像

绑定phase执行

将插件绑定在某个phase执行,在很多场景下,我们有这样的需求,例如执行mvn clean package 时,自动地为我们构建docker镜像,可以吗?答案是肯定的。我们只需要将插件的goal 绑定在某个phase即可。所谓的phase和goal,可以这样理解:maven命令格式是:mvn phase:goal ,例如mvn package docker:build 那么,package 和 docker 都是phase,build 则是goal 。在插件中配置

<executions>
    <execution>
        <id>build-image</id>
        <phase>package</phase>
        <goals>
            <goal>build</goal>
        </goals>
    </execution>
</executions>

本例指的是讲docker的build目标,绑定在package这个phase上。也就是说,用户只需要执行mvn package ,就自动执行了mvn docker:build

编译生成镜像

运行maven命令 mvn package打包并生成镜像,控制台出现如下日志,说明打包成功

F:\WorkTool\jdk1.8.0_77\bin\java.exe -Dmaven.multiModuleProjectDirectory=F:\workSpace\ideaSpace\spring-boot-demo "-Dmaven.home=D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.6\plugins\maven\lib\maven3" "-Dclassworlds.conf=D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.6\plugins\maven\lib\maven3\bin\m2.conf" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.6\lib\idea_rt.jar=58209:D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.6\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\JetBrains\IntelliJ IDEA 2018.1.6\plugins\maven\lib\maven3\boot\plexus-classworlds-2.5.2.jar" org.codehaus.classworlds.Launcher -Didea.version=2018.1.6 -s F:\mavenRepository\settings.xml -Dmaven.repo.local=F:\mavenRepository\m2\repository install -f pom.xml
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-boot-demo 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ spring-boot-demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 3 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ spring-boot-demo ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ spring-boot-demo ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] skip non existing resourceDirectory F:\workSpace\ideaSpace\spring-boot-demo\src\test\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ spring-boot-demo ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ spring-boot-demo ---
[INFO] 
[INFO] --- maven-jar-plugin:3.2.0:jar (default-jar) @ spring-boot-demo ---
[INFO] Building jar: F:\workSpace\ideaSpace\spring-boot-demo\target\spring-boot-demo-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.5.3:repackage (repackage) @ spring-boot-demo ---
[INFO] Replacing main artifact with repackaged archive
[INFO] 
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ spring-boot-demo ---
[INFO] Installing F:\workSpace\ideaSpace\spring-boot-demo\target\spring-boot-demo-1.0-SNAPSHOT.jar to F:\mavenRepository\m2\repository\org\springframework\boot\spring-boot-demo\1.0-SNAPSHOT\spring-boot-demo-1.0-SNAPSHOT.jar
[INFO] Installing F:\workSpace\ideaSpace\spring-boot-demo\pom.xml to F:\mavenRepository\m2\repository\org\springframework\boot\spring-boot-demo\1.0-SNAPSHOT\spring-boot-demo-1.0-SNAPSHOT.pom
[INFO] 
[INFO] --- docker-maven-plugin:0.4.12:build (default) @ spring-boot-demo ---
[INFO] Copying F:\workSpace\ideaSpace\spring-boot-demo\target\spring-boot-demo-1.0-SNAPSHOT.jar -> F:\workSpace\ideaSpace\spring-boot-demo\target\docker\spring-boot-demo-1.0-SNAPSHOT.jar
[INFO] Copying F:\workSpace\ideaSpace\spring-boot-demo\src\main\resources\application.yml -> F:\workSpace\ideaSpace\spring-boot-demo\target\docker\application.yml
[INFO] Copying F:\workSpace\ideaSpace\spring-boot-demo\src\main\resources\Dockerfile -> F:\workSpace\ideaSpace\spring-boot-demo\target\docker\Dockerfile
[INFO] Copying F:\workSpace\ideaSpace\spring-boot-demo\src\main\resources\templates\index.html -> F:\workSpace\ideaSpace\spring-boot-demo\target\docker\templates\index.html
[INFO] Copying F:\workSpace\ideaSpace\spring-boot-demo\src\main\resources\templates\TestFile.txt -> F:\workSpace\ideaSpace\spring-boot-demo\target\docker\templates\TestFile.txt
[INFO] Building image lushunjian/spring-boot-demo
Step 1/6 : FROM java:8

 ---> d23bdf5b1b1b
Step 2/6 : VOLUME /tmp

 ---> Using cache
 ---> d53d269ecf52
Step 3/6 : ADD spring-boot-demo-1.0-SNAPSHOT.jar app.jar

 ---> 0593cb47509e
Step 4/6 : RUN bash -c 'touch /app.jar'

 ---> Running in 1432ce028810
Removing intermediate container 1432ce028810
 ---> e914934fdff7
Step 5/6 : EXPOSE 8090

 ---> Running in 890de24d1aca
Removing intermediate container 890de24d1aca
 ---> 0dbfc3addc50
Step 6/6 : ENTRYPOINT ["java","-jar","/app.jar"]

 ---> Running in 36239d0d5310
Removing intermediate container 36239d0d5310
 ---> 0f7d64a0de0e
ProgressMessage{id=null, status=null, stream=null, error=null, progress=null, progressDetail=null}
Successfully built 0f7d64a0de0e
Successfully tagged lushunjian/spring-boot-demo:latest
[INFO] Built lushunjian/spring-boot-demo
[INFO] Tagging lushunjian/spring-boot-demo with 1.0-SNAPSHOT
[INFO] Tagging lushunjian/spring-boot-demo with latest
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.133 s
[INFO] Finished at: 2021-07-25T20:32:23+08:00
[INFO] Final Memory: 38M/745M
[INFO] ------------------------------------------------------------------------

Process finished with exit code 0

同时在Docker Desktop中可以看到刚刚成功推上去的镜像

点击右边蓝色按钮的RUN可以启动容器,容器启动前需要配置本地端口,可以看到容器端口是在Dockerfile中指定的端口,而本地端口是容器对外映射的端口(也就是访问端口),这里我填了8080

运行后,可以在Containers项看到正在运行的容器,可以看到刚刚跑起来的容器运行在8080端口

我们可以在本地通过浏览器访问8080端口,看是否正常

访问接口后正常返回了数据,说明服务已经在docker中正常运行

发布镜像到DockerHub

在最开始时我创建了一个镜像仓库 lushunjian/spring-boot-demo,在Docker的maven插件配置中有一个配置项,这个配置项的值很重要,它应该和远程仓库路径保持一致,这里我配置成了两个变量

<imageName>${docker.image.prefix}/${project.artifactId}</imageName>

<!-- 的远程仓库路径为lushunjian/spring-boot-demo,所以它的值应该是配成 -->
<imageName>lushunjian/spring-boot-demo</imageName>

大家根据自己的修改这个配置值,接下来第二步,需要配置远程仓库的服务地址,这里配置需要配置在Maven的 settings.xml文件中(一开始我是想配置pom中的,因为这样对于初学者来说比较简单直观,后面尝试了很久发现行不通)。在settings.xml加入如下配置

<servers>
    <server>
        <id>docker-hub</id>
        <username>DockerHub 的账号</username>
        <password>DockerHub 的密码</password>
        <configuration>
            <email>admin@qq.com</email>
        </configuration>
    </server>
</servers>

然后在插件的配置中加入如下配置关联上述server id

<serverId>docker-hub</serverId>

至此配置全部完毕了,接下来执行插件的命令 docker:push 即可

刷新dockerHub的仓库,会发现刚刚提交上来了两个镜像


Author: 顺坚
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 顺坚 !
评论
 Previous
关于股票买卖 关于股票买卖
股票(stock)是股份公司所有权的一部分,也是发行的所有权凭证,是股份公司为筹集资金而发行给各个股东作为持股凭证并借以取得股息和红利的一种有价证券。股票是资本市场的长期信用工具,可以转让,买卖,股东凭借它可以分享公司的利润,但也要承担公司
2021-09-05
Next 
Webpack打包原理 Webpack打包原理
近年来 Web 应用变得更加复杂与庞大,Web 前端技术的应用范围也更加广泛。 从复杂庞大的管理后台到对性能要求苛刻的移动网页,再到类似 ReactNative 的原生应用开发方案,Web 前端工程师在面临更多机遇的同时也会面临更大的挑战。
2021-06-30
  TOC