前言
目前正在出一个Docker
系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~
Docker
大家应该都听说过,特别是在当今云原生爆火的时代,更值得我们去学习,下面会带大家系统性的认识一下Docker
,并结合一些例子,让大家快速上手~
好了, 废话不多说直接开整吧~
构建镜像
前面几节都是使用的第三方镜像,那如何构建自己的应用镜像呢?在docker
中提供了build
命令
语法:
docker build [OPTIONS] PATH | URL | -
OPTIONS
说明:
--build-arg=[] :设置镜像创建时的变量; --cpu-shares :设置 cpu 使用权重; --cpu-period :限制 CPU CFS周期; --cpu-quota :限制 CPU CFS配额; --cpuset-cpus :指定使用的CPU id; --cpuset-mems :指定使用的内存 id; --disable-content-trust :忽略校验,默认开启; -f :指定要使用的Dockerfile路径; --force-rm :设置镜像过程中删除中间容器; --isolation :使用容器隔离技术; --label=[] :设置镜像使用的元数据; -m :设置内存最大值; --memory-swap :设置Swap的最大值为内存+swap,"-1"表示不限swap; --no-cache :创建镜像的过程不使用缓存; --pull :尝试去更新镜像的新版本; --quiet, -q :安静模式,成功后只输出镜像 ID; --rm :设置镜像成功后删除中间容器; --shm-size :设置/dev/shm的大小,默认值是64M; --ulimit :Ulimit配置。 --squash :将 Dockerfile 中所有的操作压缩为一层。 --tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。 --network: 默认 default。在构建期间设置RUN指令的网络模式
在大部分情况下,构建本地镜像都依赖Dockerfile
文件,通过它可以定义一些属性
如果依赖当前目录下的Dockerfile
,我们可以这么写:
docker build -t web/web:latest .
当然也可以指定文件:
docker build -f ./docker/Dockerfile -t web/web:latest .
大部分情况,使用第一种的会比较多,因为一般我们都会将文件放到项目的根目录下,这个可以根据自己的设定进行调整
我们知道了具体的命令后,下面就一起看一下Dockerfile
的语法
Dockerfile
首先Dockerfile
是一个文件,在它的文件中,我们可以定义诸多命令,你也可以比作是linux
的shell
脚本,在脚本中定义了一些命令来自动化的执行一些事情。在Dcokerfile
中,我们通常称为指令
,我们可以通过指令一步步构建自己的应用镜像
所以它有特定的语法,需要注意的是linux
中的命令不适用于Dockerfile
,这里大家要区分开,下面我们就一起看下有哪些指令吧
FROM
指定父镜像,指定Dockerfile基于那个image构建
MAINTAINER
作者信息,用来标明这个Dockerfile
谁写的
LABEL
标签,用来标明Dockerfile
的标签,可以使用Label
代替Maintainer
,最终都是在docker image
基本信息中可以查看
RUN
执行命令, 执行一段命令,默认是/bin/sh
格式: RUN command
或者 RUN [“command” , “param1”,”param2”]
CMD
指定容器创建时的默认命令。
ENTRYPOINT
设置容器创建时的主要命令。(不可被覆盖)比如我们部署服务端的应用,服务的启动命令就写在这
COPY
复制文件, build
的时候复制文件到镜像
中,比如在制作前端应用的镜像时,我们可以直接将打包好的html,js,css
静态资源放到镜像里,而不用在镜像中再打包,可以提高镜像的构建速度和减少镜像大小,从而提高应用交付的效率。比如在构建java
应用的时候,我们只需要将jar包
复制进去,在构建go
应用的时候只需要将构建完的可执行文件
放进去,然后使用CMD
命令将之启动即可。
这里需要注意的是,尽量不要将整个项目拷贝进去,因为可能会涉及到源码泄露等安全问题(因为也可以将镜像的内容拷贝到本地),而且拷贝了无关的文件也会撑大镜像的体积,构建效率会大大缩减
ADD
添加文件,build
的时候添加文件到image
中 不仅仅局限于当前build
上下文,可以来源于远程服务
ENV
环境变量, 指定build
时候的环境变量 可以在启动的容器的时候 通过-e
覆盖 格式ENV name=value
,服务可以通过读取环境变量从而达到复用的效果,而不是在代码中写死,在构建镜像的时候,也方便扩展
ARG
构建参数,只在构建的时候使用的参数 如果有ENV
那么ENV
的相同名字的值始终覆盖arg
的参数
VOLUME
定义外部可以挂载的数据卷, 指定build
的image
那些目录可以启动的时候挂载到文件系统中,启动容器的时候使用-v
绑定,格式 VOLUME ["目录"]
,比如我们可以将配置文件挂载到数据卷,那么需要改动配置的时候,我们只需要在外部(宿主主机)的配置文件,然后重启容器即可,就不用进入容器中再修改了。比如可以将data
,logs
挂载到数据卷,防止容器销毁的时候数据丢失,在容器重新创建的时候,将这些数据卷再挂载回去,就会恢复之前的应用状态
我们在部署第三方镜像的时候,可以通过docker run -v
命令来挂载数据卷,在生产中一定要挂载,不然容器被销毁了数据就全丢失了,一般官方给的部署示例中都会有
EXPOSE
暴露端口,定义容器运行的时候监听的端口 启动容器的使用-p
来绑定暴露端口 格式:EXPOSE 8080
或者 EXPOSE 8080/udp
。 我们知道容器是封闭状态,外部是无法与容器通信的,我们可以通过暴露容器端口,将容器内部应用的端口映射出去,外部(宿主主机)就可以通过暴露的端口与容器进行通信了,这里要注意的是容器内占用的端口只是容器内的,不会占用宿主主机的端口
一般情况下,我们会run
的时候指定
WORKDIR
工作目录,指定容器内部的工作目录 如果没有创建则自动创建,如果指定/
使用的是绝对地址 如果不是/
开头那么是在上一条workdir
的路径的相对路径,我们可以将打包好的应用放到指定目录下去执行,这个跟我们在服务器指定目录下部署服务是一个道理
USER
指定执行用户,指定build
或者启动的时候用户, 在RUN CMD ENTRYPONT
执行的时候的用户
HEALTHCHECK
健康检查,指定监测当前容器的健康监测的命令,大部分情况下用不到,因为容器本身有检查机制
ONBUILD
触发器,当存在ONBUILD
关键字的镜像作为基础镜像的时候 当执行FROM
完成之后 会执行 ONBUILD
的命令 但是不影响当前镜像 用处也不怎么大
STOPSIGNAL
发送信号量到宿主机,该STOPSIGNAL
指令设置将发送到容器的系统调用信号以退出,这个也不是很常用
SHELL
指定执行脚本的shell
,指定RUN CMD ENTRYPOINT
执行命令的时候 使用的shell
,这个也不是很常用
命令介绍差不多了,下面就带大家从0
构建SpringBoot
的服务镜像
@RestController @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) public class WepAppliation { @GetMapping("/hello") public String hello() { return "hello world!"; } public static void main(String[] args) { SpringApplication.run(WepAppliation.class, args); } }
默认情况下,8080
端口,测试下http://localhost:8080/hello
输出hello world!
,应用没问题,接着开始打包,将jar
包与Dockerfile
位于通个目录下
接着准备Dockerfile
# 基础镜像 FROM openjdk:8-jre # author MAINTAINER pkq # 挂载目录 VOLUME /root/java/app-web-docker # 创建目录 RUN mkdir -p /app # 指定路径 WORKDIR /app # 复制jar文件到路径 COPY ./app-web.jar /app/app-web.jar # 启动服务 ENTRYPOINT ["java", "-jar", "app-web.jar"]
这里我使用的基础镜像是openjdk:8-jre
,这个是比较小的镜像,大家在选取基础镜像
的时候,在满足需求的情况下尽可能的小
,动辄几个G的镜像那肯定是不行的,因为太大的镜像影响构建速度还会占用服务器的资源,如果要推送到远端仓库会比较慢
接着我们执行
>>>> docker build -t app-web . [root@iZ2ze5vrnucj8nu52fq932Z app-web-docker]# docker build -t app-web . Sending build context to Docker daemon 53.23 MB Step 1/7 : FROM openjdk:8-jre Trying to pull repository docker.io/library/openjdk ... 8-jre: Pulling from docker.io/library/openjdk 0e29546d541c: Pull complete 9b829c73b52b: Pull complete cb5b7ae36172: Pull complete 99ce012bef04: Pull complete 22dc2a72d098: Pull complete 9c69a57e10d9: Pull complete Digest: sha256:c0ab1c0631266ef9420a414726a790733a2561efc5f4fa2f9b8186f4d6b00d53 Status: Downloaded newer image for docker.io/openjdk:8-jre ---> 26ac3f63d29f Step 2/7 : MAINTAINER pkq ---> Running in 085e5fc91fac ---> 59c6ebf2ddba Removing intermediate container 085e5fc91fac Step 3/7 : VOLUME /root/java/app-web-docker ---> Running in 3aa1858ced18 ---> 3ad95bbbe6ef Removing intermediate container 3aa1858ced18 Step 4/7 : RUN mkdir -p /app ---> Running in ddce902c1044 ---> a0434002b4ef Removing intermediate container ddce902c1044 Step 5/7 : WORKDIR /app ---> 4ec0a0a8b000 Removing intermediate container 50b90491e870 Step 6/7 : COPY ./app-web.jar /app/app-web.jar ---> 4457507b2c81 Removing intermediate container 532dd4d4f748 Step 7/7 : ENTRYPOINT java -jar app-web.jar ---> Running in f8b25a13a3ae ---> e7ea93a81515 Removing intermediate container f8b25a13a3ae Successfully built e7ea93a81515 [root@iZ2ze5vrnucj8nu52fq932Z app-web-docker]# [root@iZ2ze5vrnucj8nu52fq932Z app-web-docker]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE app-web latest e7ea93a81515 About a minute ago 327 MB
可以看到镜像已经构建成功了,下面运行测试一下
>>>docker run -it -d -p 10000:8080 --name app-web app-web 5a9682238959ec7b54ba8cc2bff51d1494f6a1ac0e4bed4a97e330e0b0693328 [root@iZ2ze5vrnucj8nu52fq932Z app-web-docker]# docker logs -f app-web SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/app/app-web.jar!/BOOT-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/app/app-web.jar!/BOOT-INF/lib/slf4j-simple-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder] . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.3.RELEASE) 2023-10-26 02:57:06.625 INFO 1 --- [ main] com.jbp.web.WepAppliation : Starting WepAppliation v1.0-SNAPSHOT on 5a9682238959 with PID 1 (/app/app-web.jar started by root in /app) 2023-10-26 02:57:06.635 INFO 1 --- [ main] com.jbp.web.WepAppliation : No active profile set, falling back to default profiles: default 2023-10-26 02:57:11.330 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2023-10-26 02:57:11.439 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2023-10-26 02:57:11.440 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.16] 2023-10-26 02:57:11.471 INFO 1 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib] 2023-10-26 02:57:11.664 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2023-10-26 02:57:11.664 INFO 1 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4845 ms 2023-10-26 02:57:13.455 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2023-10-26 02:57:14.718 INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator' 2023-10-26 02:57:15.027 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2023-10-26 02:57:15.042 INFO 1 --- [ main] com.jbp.web.WepAppliation : Started WepAppliation in 9.563 seconds (JVM running for 10.509)
看到已经运行成功了,试试请求是否成功,因为我暴露的10000
端口,所以请求curl http://localhost:10000/hello
[root@iZ2ze5vrnucj8nu52fq932Z app-web-docker]# curl http://localhost:10000/hello hello world! [root@iZ2ze5vrnucj8nu52fq932Z app-web-docker]#
可以看到成功运行了~ 大家可以举一反三,试着构建一些其它服务
结束语
本节到这里就结束了,docker
命令很多,大家不要去背,如果忘了可以使用docker -h
进行查看,多动手,多尝试,多踩坑,下节继续给大家讲解它的用法~
本着把自己知道的都告诉大家,如果本文对有所帮助,点赞+关注
鼓励一下呗~