一、什么是Dockerfile?
Dockerfile是一个创建镜像所有命令的文本文件, 包含了一条条指令和说明, 每条指令构建一层, 通过docker build命令,根据Dockerfile的内容构建镜像。
因此每一条指令的内容, 就是描述该层如何构建.有了Dockefile, 就可以制定自己的docker镜像规则,只需要在Dockerfile上添加或者修改指令, 就可生成docker 镜像.
意义?
到这里是不是很多人和我一样,docker是不是就敲几个命令就行了呢?项目打包交给运维就行了,我们编码人员一定要掌握docker吗?到底应该怎么用在我们项目中去?
在这里我想说,对于任何一门技术的诞生都有它存在的意义,在任何时代,一门技术的流行,都是为了给开发提高效率,节约时间和成本,不是越来越复杂,而是把以前复杂的东西简单化,这就是它存在以及流行的目的。
所以对于程序员来说不要排斥它,要永远抱有一种好奇和学习的心态。
下面会分两种方式讲解怎么构建我们的项目镜像。
二、Dockerfile常用指令介绍
FROM: 指定基础镜像
MAINTAINER:维护者信息
RUN:执行命令(每执行一条RUN命令,镜像添加新的一层)
shell 格式: RUN <命令> ,RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html exec 格式: RUN ["可执行文件", "参数1", "参数2"] 。run可以写多个,每一个指令都会建立一层,所以正确写法应该是↓ RUN buildDeps='gcc libc6-dev make' \ && apt-get update \ && apt-get install -y $buildDeps \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \ && mkdir -p /usr/src/redis \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && make -C /usr/src/redis \ && make -C /usr/src/redis install \ && rm -rf /var/lib/apt/lists/* \ && rm redis.tar.gz \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps
COPY:复制文本
COPY <源路径>...<目标路径>
<源路径> :
源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/ COPY hom?.txt /mydir/<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
ADD:高级复制文件
ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
ENTRYPOINT
- CMD 在docker run 时运行。
- RUN 是在 docker build。
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
格式:
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]示例:
假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx ENTRYPOINT ["nginx", "-c"] # 定参 CMD ["/etc/nginx/nginx.conf"] # 变参1、不传参运行
$ docker run nginx:test容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf2、传参运行
$ docker run nginx:test -c /etc/nginx/new.conf容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
nginx -c /etc/nginx/new.confENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:
ENV <key> <value> ENV <key1>=<value1> <key2>=<value2>...VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
格式:
VOLUME ["<路径1>", "<路径2>"...] VOLUME <路径>在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
EXPOSE
仅仅只是声明端口。
作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:
EXPOSE <端口1> [<端口2>...]
三、DockerFile构建本地java项目
1、准备。
①、首先,需要在IDEA中下载插件
②、其次,准备一个docker服务器。docker服务器安装在windows上,还是linux上都可以。这边准备的是地址为172.16.9.115一个本地搭建的linux系统,docker环境已经安装完毕
2.修改端口
打开/usr/lib/systemd/system/下的docker.service
vi /usr/lib/systemd/system/docker.service
# 在ExecStart=/usr/bin/dockerd后追加,如下: ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
# 重新加载服务的配置文件 systemctl daemon-reload # 重启docker服务 systemctl restart docker
3.idea连接docker
连接成功之后,前面说了需要安装一个docker插件。
直接打开docker插件,看前面连接成功能不能直接看到我们服务器上的docker中的容器和镜像
4.项目构建镜像。
准备工作:提前准备好一个案例项目。
这里推荐两种方式:
①、dockerfile-maven-plugin插件
步骤1:
在pom.xml安装dockerfile-maven-plugin插件,并做相应的配置:
<plugin> <groupId>com.spotify</groupId> <artifactId>dockerfile-maven-plugin</artifactId> <version>1.3.7</version> </plugin>步骤2:
在项目的根目录下创建名为DockerFile文件
配置DockerFile
FROM jdk1.8:latest MAINTAINER docker WORKDIR / # 把target下的sharding-jdbc-server-2.2.2-SNAPSHOT.jar,sharding-jdbc-server-2.2.2-SNAPSHOT.jarADD target/sharding-jdbc-server-2.2.2-SNAPSHOT.jar /sharding-jdbc-server-2.2.2-SNAPSHOT.jar # 对外暴露的端口 EXPOSE 8097 ENTRYPOINT ["java","-jar","/sharding-jdbc-server-2.2.2-SNAPSHOT.jar"]步骤3:通过插件将生成好的镜像打到服务器上去
打包之前先 maven clean 然后再执行maven package
先配置docker插件配置dockerFile
这里需要重点说一下绑定的端口:
对于镜像来说,它是分层镜像的,前面我也说到了,我们的jar包被打进镜像的某一层存储着,当我们运行成容器,我们的项目也是随容器开始执行,可以说是执行在该容器中,我们访问这个容器需要提供一个外部端口
来供我们访问,内部端口其实就是对应的容器我们服务的端口,将这两个端口进行绑定(映射),其实我们在外部就可用过这个外部端口直接访问我们项目了
找到dockerFile文件
有两种方式:
方式1:打成镜像生成容器运行
方式2:仅仅打成镜像
这边我选择方式1
发现已经成功打好镜像,并生成容器运行,容器名称镜像名称都是上面docker插件里面配置的
现在试一下,访问一个接口
http://172.16.9.115:8097/sharding/person/add
上图发现成功执行了
②、docker-maven-plugin插件的方式
这种方式相对来说要简单许多。
步骤1:
在pom.xml安装dockerfile-maven-plugin插件,并做相应的配置:
<plugin> <groupId>com.spotify</groupId> <artifactId>docker-maven-plugin</artifactId> <version>1.2.1</version> <configuration> <imageName>${project.artifactId}:${project.version}</imageName> <imageTags> <imageTag>${project.version}</imageTag> </imageTags> <dockerDirectory>${project.basedir}</dockerDirectory> <dockerHost>http://172.16.9.115:2375</dockerHost> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}</include> </resource> </resources> </configuration> <!--执行mvn package,即执行 mvn clean package docker:build--><executions> <execution> <id>build-image</id> <phase>package</phase> <goals> <goal>build</goal> </goals> </execution> </executions> </plugin>这里有几个标签需要注意一下
<imageName />:镜像名称<imageTags>:指定标签<dockerDirectory>:要构建的服务地址<directory>:用于指定需要复制的根目录,${project.build.directory}表示target目录<include>:用于指定需要复制的文件,${project.build.finalName}.jar就是打包后的target目录下的jar包名称这个方式比较简单,在插件里面配置我上面的内容,直接mvn clean maven package就可以打上镜像了
然后在服务器上找到该镜像,启动它
现在看一下效果
postman请求一个接口:
四、可视化平台管理工具Portainer
前面介绍了一个可视化平台工具portainer,系统化看一下我们对于docker要关注什么?
关键字:
Statck:stack就是一组有关联的服务的组合,可以编排在一起,一起管理。比如swarm集群中可以把一系列的服务组合起来。
Services:swarm集群中可以将服务分配到各个节点上一群组合服务,其包括stack
Containers:当前服务器容器列表查看
Images:可以对当前服务器镜像列表查看
Volumes:文件挂载,可以容器创建之前把容器文件与主机文件联系到一起
Networks:网络。可以自定义配置,让集群的服务在一个网段。后面集群的时候会讲到。
容器:
标签:
start:启动容器
stop:停止容器,与start搭配使用
kill:停止容器,与stop不同的是stop是先发送SIGTERM信号,在一段时间之后(10s)再发送SIGKILL信号可以做一些“退出前工作”,比如保存状态、处理当前请求等。kill直接发送SIGKILL信号。
Restart:重新启动容器
Pause:暂停容器
Resume:恢复容器与pause搭配使用
Remove:删除容器,先关闭再删除
Recreate:重新构建容器(先删除之前的容器再构建),如果这期间有新的未保存的数据就会被丢失
Duplicate/Edit:和Recreate效果一样,根据之前的容器镜像信息构建容器,但不同的是,可以修改先前容器信息比如port,挂载,Network,Env等等。
演示:重新构建本地镜像,在这基础上通过控制台手动构建容器。
目前我的环境中有一个我们项目的镜像
重新构建后:
进入控制台,重新创建容器
还是根据镜像名称来重新创建容器: