使用docker部署程序–使用Dockerfile将程序打包成镜像
1 Dockerfile的命令
1.1 基础镜像信息
FROM
指定哪个镜像作为新镜像的基础镜像
1.2 维护者信息
MAINTAINER
指明该镜像的作者信息
1.3 镜像操作指令
1.3.1 RUN
在新镜像内部执行的命令,比如安装一些软件、配置一些基础环境,可使用\来换行
RUN echo 'hello docker!' \
> /usr/local/file.txt
也可以使用exec格式RUN ["executable", "param1", "param2"]
的命令,如:
RUN ["apt-get","install","-y","nginx"]
要注意的是,executable是命令,后面的param是参数
1.3.2 COPY
将主机的文件复制到镜像内,如果目的位置不存在,Docker会自动创建所有需要的目录结构,但是它只是单纯的复制,并不会去做文件提取和解压工作。如:
COPY application.yml /etc/springboot/hello-service/src/resources
注意:需要复制的目录一定要放在Dockerfile文件的同级目录下
原因:因为构建环境将会上传到Docker守护进程,而复制是在Docker守护进程中进行的。任何位于构建环境之外的东西都是不可用的。COPY指令的目的的位置则必须是容器内部的一个绝对路径。
《THE DOCKER BOOK》
1.3.3 ADD
将主机的文件复制到镜像中,跟COPY一样,限制条件和使用方式都一样,如:
ADD application.yml /etc/springboot/hello-service/src/resources
但是ADD会对压缩文件(tar, gzip, bzip2, etc)做提取和解压操作。
1.3.4 EXPOSE
暴露镜像的端口供主机做映射,启动镜像时,使用-P参数来讲镜像端口与宿主机的随机端口做映射。使用方式(可指定多个):
EXPOSE 8080
EXPOSE 8081
...
1.3.5 WORKDIR
在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录。如
WORKDIR /usr/local
WORKDIR webservice
RUN echo 'hello docker' > text.txt
...
最终会在/usr/local/webservice/目录下生成text.txt文件
1.3.6 ONBUILD
当一个包含ONBUILD命令的镜像被用作其他镜像的基础镜像时(比如用户的镜像需要从某为准备好的位置添加源代码,或者用户需要执行特定于构建镜像的环境的构建脚本),该命令就会执行。
如创建镜像image-A
FROM ubuntu
...
ONBUILD ADD . /var/www
...
然后创建镜像image-B,指定image-A为基础镜像,如
FROM image-A
...
然后在构建image-B的时候,日志上显示如下:
Step 0 : FROM image-A
# Execting 1 build triggers
Step onbuild-0 : ADD . /var/www
...
1.3.7 USER
指定该镜像以什么样的用户去执行,如:
USER mongo
1.3.8 VOLUME
用来向基于镜像创建的容器添加卷。比如你可以将mongodb镜像中存储数据的data文件指定为主机的某个文件。(容器内部建议不要存储任何数据)
如:
VOLUME /data/db /data/configdb
注意:VOLUME 主机目录 容器目录
1.3.9 CMD
容器启动时需要执行的命令,如:
CMD /bin/bash
同样可以使用exec语法,如
CMD ["/bin/bash"]
当有多个CMD的时候,只有最后一个生效。
1.4 其他
其他命令参考官方文档:https://docs.docker.com/engine/reference/builder/
2 实例演示
下面演示一下如何使用Dockerfile将SpringBoot构建的jar打包成镜像:
2.1 准备工作
首先系统要安装好Docker,这里不在介绍,可以参考:安装docker
然后写一个简单的SpringBoot程序并构建打包,程序的主要功能就是,访问http://ip+port/hello时返回"hello":
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello";
}
}
2.2 使用命令行构建
使用的Docker的版本:
➜ target docker --version
Docker version 18.09.1, build 4c52b90
Dockerfile文件如下:
#使用的基础镜像,构建时本地没有的话会先下载
FROM java:latest
#添加jar包
ADD ./*.jar app.jar
#暴露的端口
EXPOSE 8080
#容器运行后执行的命令,设置镜像的时区为上海,然后运行程序
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
ENTRYPOINT ["java","-jar","/app.jar"]
构建镜像时,使用docker build
命令,具体可以用docker build --help
查看,或者查看教程:docker build命令
注意:
- Dockerfile文件可以放在本地,也可以放在github上。
- Dockerfile文件必须命名为
Dockerfile
或者dockerfile
,没有后缀名!
这里使用本地的文件:
# -t 指定生成的镜像的tag,./指定docker的文件所在的目录
docker build -t thetop/hello:v1 ./
构建后查看本地镜像库,已经有了thetop/hello
这个镜像:
➜ target docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thetop/hello v1 ae8c5af0e53b About a minute ago 660MB
java latest d23bdf5b1b1b 2 years ago 643MB
运行构建的镜像:
➜ target docker run -it -p 8080:8080 thetop/hello:v1
2.3 使用Intellij idea构建
2.3.1 链接Docker
链接Docker的设置路径为:File | Settings | Build, Execution, Deployment | Docker
**注意:**链接远程Docker要在远程Docker的配置文件中进行配置
2.3.2 Docker开启远程访问
默认情况下,Docker使用守护进程Unix socket(/var/run/docker.sock)来进行本地进程通信,而不会监听任何端口,因此只能在本地使用docker客户端或者使用Docker API进行操作。如果想在其他主机上操作Docker主机,就需要让Docker守护进程打开一个HTTP Socket,这样才能实现远程通信。
编辑docker的配置文件/etc/default/docker修改DOCKER_OPTS为:
#同时监听本地unix socket和远程http socket(2375)
DOCKER_OPTS="-H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375"
然后重新启动docker守护进程。
sudo systemctl restart docker
注意:
- 记得开放使用的端口
- **公网服务器不建议使用2375这个端口!**它是Docker的默认端口,而且链接Docker时不需要进行身份验证,很有可能被黑客利用!我就遇到了开启默认端口后多出来一些奇怪的镜像和运行着的容器,大致看了一下它运行的命令,应该是被做成tor的节点,而且还留了可以登录的后门。
2.3.3 构建镜像
在工程的根目录下创建Dockerfile文件,然后点击Dockerfile中FROM指令左边的运行按钮,可以选择build镜像,也可以选择编辑Dockerfile文件:
在这里选择编辑Dockerfile文件,可以使用窗口编辑Dockerfile文件,对Dockerfile的新手来说非常友好,但是最大的坏处是不能将修改固化到Dockerfile文件中,转移Dockerfile之后就需要重新编辑,点击Run按钮进行创建镜像和容器:
创建后的镜像: