手记

Docker部署Spring boot 应用 快速入门

一.关于 Docker

docker 可以理解是运行Linux和Mac OS X上的轻量级虚拟机,他相对于VMWare,Virtual Box这类完整的虚拟机相比,占用资源少,大量重用宿主资源,而且可以编程创建. 而且可以统一开发,测试和发布环境,是运行基于Linux后台服务器的利器.

有三个重要概念

  • 镜像(Image)

  • 容器(Container)

  • 仓库(Repository)

理解了这三个概念,就理解了 Docker 的整个生命周期。

Docker 镜像

Docker 镜像就是一个只读的模板。镜像的定义文件取名为 Dockerfile. 类似于shell格式

Docker 容器

Docker 利用容器来运行应用。

容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。

可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

Docker 仓库

仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。

仓库分为公开仓库(Public)和私有仓库(Private)两种形式。

最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括Docker Pool 等,可以提供大陆用户更稳定快速的访问。

二.关于spring boot 的Docker 发布准备

发布形式

spring boot 为了简化开发,可以把应用,tomcat 服务统一打包在一个jar中,因此在Docker 发布spring boot 可以直接拷贝最终jar到docker中,另外一种方法把源码拷入docker 在,docker里面下载编译工具maven,jdk等自行编译,后面一种方法构建docker用时较长,每次都是重新下载相关jar依赖编译,不推荐.

因此我们假设已经在本机编译好jar,每拷入这个jar即可.

代码准备

用 IDEA或Eclipse 配置发布版有一点步骤,为了简单操作,我们直接采用maven 命令来编译一个简单的Spring boot项目.

程序的输出很简单,在浏览器访问docker 对应端口,输出一行提示,

我们手动构造一个简单项目

mkdir hello-docker ; cd hello-docker # 项目目录

编辑pom.xml

<?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>

    <groupId>cn.bluedrum.springdemo</groupId>
    <artifactId>bluedrum-spring-boot-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.1.RELEASE</version>
        <relativePath/>
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <docker.image.prefix>springio</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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>


            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.4.13</version>
                <configuration>
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>
    </build></project>

编辑源代码

mkdir -p src/main/java/cn/bluedrum/springdemo

在springdemo创建java文件 SampleController.java

package cn.bluedrum.springdemo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controller@SpringBootApplicationpublic class SampleController {    @ResponseBody
    @RequestMapping(value = "/")    String home(){        return "Hello Docker World2";
    }    public static void main(String[] args) {
        SpringApplication.run(SampleController.class,"--server.port=8081");
    }
}

注意 "--server.port=8081",表示启动tomcat 端口是8081(而不是缺省的8080)

编译成 jar

这里要安装maven,
编译成jar

mvn package

本地测试,需要安装jdk
运行:

java -jar target/bluedrum-spring-boot-demo-1.0-SNAPSHOT.jar

如果程序正确运行,浏览器访问 http://localhost:8081/,可以看到页面 “Hello Docker World2” 字样

三.本地Docker 发布

Docker 标准推荐操作系统是 Ubuntu 64位,如 14.04 ,16.06版本. 其它的操作系统的需要使用置virtual box 虚拟机上的Ubuntu上运行Docker,

但 新的Docker 在Mac 下开发的一个 MacOS Hypervisor framework,相当于在其构造一个性能很高的专用虚拟机.

因此在你看这篇文章时,Mac OSX和Ubuntu 64均是标准的Docker 安装环境.

Mac OS X安装

可以下载 Docker 社区版,安装
https://store.docker.com/editions/community/docker-ce-desktop-mac

安装后会有一个图标出现在顶部

image.png

所有配置均可用图形界面,为了提高docker image 下载速度,可以使用
国内docker 加速网站,
常见有 http://www.daocloud.io/mirror
阿里云的加速服务 http://dev.aliyun.com

image.png


构建本地docker 容器

首先要编辑Dockerfile 文件

FROM java:8
EXPOSE 8081
VOLUME /tmp
ADD bluedrum-spring-boot-demo-1.0-SNAPSHOT.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]

以下是解释
FROM 表示本image是哪一个基础image继承而来, java:8是带有jdk8运行环境的image

EXPOSE 8081  表示本docker 要把本地8081进行映射,这个测试在mac下无所谓,但在阿里云这样docker 必须有这一句,否则映射会失败.

VOLUME /tmp  VOLUME 指定了数据文件目录为/tmp。其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp ,这样做是因为docker 重启后所有数据丢失,持久数据保存在VOLUME指定目录下才会下次使用.

ADD表示把文件拷入docker ,并改名成 app.jar

ENTRYPOINT 表示docker 启动执行第一个指令,这里是调用java 启动 jar

命令行构建

构建容器方法有两种,一种是调用docker build 指令手动建
在Dockerfile 所在目录执行如下指令(注意,这个jar必须和Dockerfile同一路径下)

docker build -t hxy .

build表示构建容器,. 表示构建文件在当前目录. -t 指明本容器的tag名字,方便调用.

这是一个成功调用,

docker build -t hxy .
Sending build context to Docker daemon  63.43MB
Step 1/7 : FROM java:8
 ---> d23bdf5b1b1b
Step 2/7 : EXPOSE 8081
 ---> Using cache
 ---> af40c4f0bb64
Step 3/7 : VOLUME /tmp
 ---> Using cache
 ---> 5a0abb6e6149
Step 4/7 : ADD bluedrum-spring-boot-demo-1.0-SNAPSHOT.jar app.jar
 ---> 135b017b65bd
Step 5/7 : RUN sh -c 'touch /app.jar'
 ---> Running in b3089dd7490a
Removing intermediate container b3089dd7490a
 ---> 472354c65e33
Step 6/7 : ENV JAVA_OPTS=""
 ---> Running in 01cec8aeaaa9
Removing intermediate container 01cec8aeaaa9
 ---> fb2dd3c02514
Step 7/7 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
 ---> Running in c2a93f997776
Removing intermediate container c2a93f997776
 ---> de32f8f2ac97
Successfully built de32f8f2ac97
Successfully tagged hxy:latest

Successfully built de32f8f2ac97 这里指明image ID. 在后续的操作中用使用

启动docker 容器

以下表示启动指定image .

docker run de32f8f2ac97  -p 8081:8081

-p <本地端口>:<docker端口> 表示把docker 端口映射到本地端口来.

测试用  http://localhost:8081 有输出即可

还有一种调用是用tag调用,不指定话默认用最新那个

docker run -t hxy -p 8081:8081

停止容器实例

docker stop  484b1a9b8a49   #用docker ps 查看
docker stop -t hxy

maven插件构建

这里也可采用maven插件docker-maven-plugin 调docker 命令,优点是编译完后自动构建,并且有推送到远程仓库功能

这里关键是在pom.xml有其申明,其中dockerDirectory 是指明Dockerfile所在目录,

 <artifactId>docker-maven-plugin</artifactId>
                <version>0.4.13</version>
                <configuration>
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <dockerDirectory>.</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>

执行命令,这里执行编译,并枸造docker 实例

mvn package docker:build

四.docker 调试

查看运行实例 docker ps

查看所有运行实例

CONTAINER ID        IMAGE                                COMMAND                  CREATED             STATUS              PORTS                    NAMES
484b1a9b8a49        de32f8f2ac97                         "sh -c 'java $JAVA_O…"   2 minutes ago       Up 2 minutes        8081/tcp                 angry_visvesvaraya
c54ede741112        springio/bluedrum-spring-boot-demo   "sh -c 'java $JAVA_O…"   2 days ago          Up 2 days           0.0.0.0:8081->8081/tcp   agitated_swirles

这里第一列 CONTAINER ID 即可容器ID,后续各项操作均要用到此ID
PORTS是用来判断网络映射状态, 如果为空,表示完全没有网络映射,如网络出问题,没有侦听服务

如果为 8081/tcp  形式表示,只在docker 启动了端口侦听,但没有映出来,因此外部是无法访问的.

0.0.0.0:8081->8081/tcp  只有这样形式,表示外部的8081端口,映射到内部端口,这样才是正常工作

docker images

查看所有image

REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
hxy                                  latest              de32f8f2ac97        About an hour ago   685MB
springio/bluedrum-spring-boot-demo   latest              7df85e003c92        2 days ago          695MB
docker-demo                          latest              af850b972103        2 days ago          669MB<none>                               <none>              da7283718e15        2 days ago          669MB<none>                               <none>              381c4e1fa40c        3 days ago          653MB<none>                               <none>              3ef8dca1797a        3 days ago          674MB
hub.c.163.com/wuxukun/maven-aliyun   3-jdk-8             676639454cb4        15 months ago       653MB
java                                 8                   d23bdf5b1b1b        16 months ago

注意这里的size 表示占用空间大小,所以本地docker 如果不用,尽量删掉

连接docker 内部控制台

有时我们想连接docker 内部的虚拟机进行各种命令来分析测试,

docker exec -ti <CONTAINER ID> bash

以下是一个例, -t 表示attach 到某个容器上,i 表示交互模式,本句完整意思在某个容器上以交互模式执行bash ,相当进入控制台.

docker exec -ti 36976f3c166b bash
root@36976f3c166b:/# uname -aLinux 36976f3c166b 4.9.87-linuxkit-aufs #1 SMP Wed Mar 14 15:12:16 UTC 2018 x86_64 GNU/Linuxroot@36976f3c166b:/# cat /proc/cpuinfoprocessor   : 0vendor_id   : GenuineIntel
cpu family  : 6model       : 42model name  : Intel(R) Core(TM) i7-2720QM CPU @ 2.20GHz

删除容器

docker rm <容器ID>
注意正在运行容器,需要用 docker stop 后才能删除

删除镜像

docker rmi <image ID>

五,在阿里云运行容器

在阿里云,我们采用ubuntu 64bit .有两种方法来运行容器,一种还是象本地操作来传统的命令行,另外一种采用阿里云的容器服务,后面相当于用网页来图形式操作,并且有日志/监控等运维界面.

本文中仍然采用命令行来运行. 以便适合主题快速入门.

安装docker

用apt安装 docker 的版本太低

apt-get install docker.io

版本为1.6

阿里云建议采用 dokcer ce版(社区版).用如下命令安装,版本较新

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

uname -a
116~14.04.1-Ubuntu SMP Mon Aug 14 16:07:05 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
docker --version
Docker version 18.05.0-ce, build f150324

修改docker 缺省配置

新版的docker 配置放在/etc/docker/daemon.json

{  "bip": "192.168.1.5/24", "debug": true, "registry-mirrors": ["https://fzxn****.mirror.aliyuncs.com"]
}

--bip 指定docker 的虚拟网卡的ip地址, 缺省的网卡地址 172.18.xxx.xxx 而阿里云内网网卡也是172.19 网段,这两个很容易冲突,造成映射失败.

"registry-mirrors" 是阿里云docker 加速网址,可到阿里云控制台申请,

启动docker

service docker start

上传文件

Dockerfile ,jar 各种文件用 scp 上传到阿里云服务器

构建运行

还是用 docker build/run 进行构建,跟本地是一样的

测试

首先用本地测试 用 curl
如果有输出即表示成功

curl http://127.0.0.1:8081
Hello Docker World2

外网测试 ,需要用阿里云控制台,用安全组打开这个端口,外网才能访问


image.png

用外网ip 或网址测试后输出后表示成功

问题测试

首先要判断一下,网卡是否有网址冲突(docker ps 中ports 为空),如有需要用 --bip参数错开私有网址
另外要有EXPOSE 指令,在本地测试时,没有expose也能映射,但阿里云必须带这个.
第三个外网访问,必须要安全组开放



作者:蓝点工坊
链接:https://www.jianshu.com/p/2a32a4fc9852

0人推荐
随时随地看视频
慕课网APP