前言
目前正在出一个Docker系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~
Docker大家应该都听说过,特别是在当今云原生爆火的时代,更值得我们去学习,下面会带大家系统性的认识一下Docker,并结合一些例子,让大家快速上手~
好了, 废话不多说直接开整吧~
构建镜像
前面几节都是使用的第三方镜像,那如何构建自己的应用镜像呢?在docker中提供了build命令
语法:
shell
docker build [OPTIONS] PATH | URL | -
OPTIONS说明:
shell
--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,我们可以这么写:
shell
docker build -t web/web:latest .
当然也可以指定文件:
shell
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的服务镜像
java
@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
shell
# 基础镜像
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的镜像那肯定是不行的,因为太大的镜像影响构建速度还会占用服务器的资源,如果要推送到远端仓库会比较慢
接着我们执行
shell
>>>> 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
可以看到镜像已经构建成功了,下面运行测试一下
shell
>>>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
shell
[root@iZ2ze5vrnucj8nu52fq932Z app-web-docker]# curl http://localhost:10000/hello
hello world!
[root@iZ2ze5vrnucj8nu52fq932Z app-web-docker]#
可以看到成功运行了~ 大家可以举一反三,试着构建一些其它服务
结束语
本节到这里就结束了,docker命令很多,大家不要去背,如果忘了可以使用docker -h进行查看,多动手,多尝试,多踩坑,下节继续给大家讲解它的用法~
本着把自己知道的都告诉大家,如果本文对有所帮助,点赞+关注鼓励一下呗~
Docker教程相关文章
往前Shell脚本编程相关文章
- 一起来学Shell脚本编程(一)
- 一起来学Shell脚本编程(二)
- 一起来学Shell脚本编程(三)
- 一起来学Shell脚本编程(四)
- 一起来学Shell脚本编程(五)
- 一起来学Shell脚本编程(六)
- 一起来学Shell脚本编程(七)
往期Linux相关文章
- 一起来学Linux命令(一)
- 一起来学Linux命令(二)
- 一起来学Linux命令(三)
- 一起来学Linux命令(四)
- 一起来学Linux命令(五)
- 一起来学Linux命令(六)
- 一起来学Linux命令(七)
- 一起来学Linux命令(八)
- 一起来学Linux命令(九)
- 一起来学Linux命令(十)
往期面试题相关文章
- 查漏补缺第一期(Redis相关)
- 查漏补缺第二期(synchronized & 锁升级)
- 查漏补缺第三期(分布式事务相关)
- 查漏补缺第四期(Mysql相关)
- 查漏补缺第五期(HashMap & ConcurrentHashMap)
- 查漏补缺第六期(京东一面)
- 查漏补缺第七期(美团到店一面)
- 查漏补缺第八期(阿里一面)
- 查漏补缺第九期(阿里二面)
- 查漏补缺第十期(网易实习一面)
- 查漏补缺第十一期(网易实习二面)
- 查漏补缺第十二期(网易实习三面)
- 查漏补缺第十三期(滴滴实习一面)
- 查漏补缺第十四期(滴滴实习二面)
- 查漏补缺第十五期(华为一面)
- 查漏补缺第十六期(华为二面)
- 查漏补缺第十七期(华为三面)
- 查漏补缺第十八期(你了解class文件吗)
项目源码(源码已更新 欢迎star⭐️)
往期设计模式相关文章
- 一起来学设计模式之认识设计模式
- 一起来学设计模式之单例模式
- 一起来学设计模式之工厂模式
- 一起来学设计模式之建造者模式
- 一起来学设计模式之原型模式
- 一起来学设计模式之适配器模式
- 一起来学设计模式之桥接模式
- 一起来学设计模式之组合模式
- 一起来学设计模式之装饰器模式
- 一起来学设计模式之外观模式
- 一起来学设计模式之享元模式
- 一起来学设计模式之代理模式
- 一起来学设计模式之责任链模式
- 一起来学设计模式之命令模式
- 一起来学设计模式之解释器模式
- 一起来学设计模式之迭代器模式
- 一起来学设计模式之中介者模式
- 一起来学设计模式之备忘录模式
- 一起来学设计模式之观察者模式
- 一起来学设计模式之状态模式
- 一起来学设计模式之策略模式
- 一起来学设计模式之模板方法模式
- 一起来学设计模式之访问者模式
- 一起来学设计模式之依赖注入模式
设计模式项目源码(源码已更新 欢迎star⭐️)
Kafka 专题学习
- 一起来学kafka之Kafka集群搭建
- 一起来学kafka之整合SpringBoot基本使用
- 一起来学kafka之整合SpringBoot深入使用(一)
- 一起来学kafka之整合SpringBoot深入使用(二)
- 一起来学kafka之整合SpringBoot深入使用(三)
项目源码(源码已更新 欢迎star⭐️)
ElasticSearch 专题学习
项目源码(源码已更新 欢迎star⭐️)
往期并发编程内容推荐
- Java多线程专题之线程与进程概述
- Java多线程专题之线程类和接口入门
- Java多线程专题之进阶学习Thread(含源码分析)
- Java多线程专题之Callable、Future与FutureTask(含源码分析)
- 面试官: 有了解过线程组和线程优先级吗
- 面试官: 说一下线程的生命周期过程
- 面试官: 说一下线程间的通信
- 面试官: 说一下Java的共享内存模型
- 面试官: 有了解过指令重排吗,什么是happens-before
- 面试官: 有了解过volatile关键字吗 说说看
- 面试官: 有了解过Synchronized吗 说说看
- Java多线程专题之Lock锁的使用
- 面试官: 有了解过ReentrantLock的底层实现吗?说说看
- 面试官: 有了解过CAS和原子操作吗?说说看
- Java多线程专题之线程池的基本使用
- 面试官: 有了解过线程池的工作原理吗?说说看
- 面试官: 线程池是如何做到线程复用的?有了解过吗,说说看
- 面试官: 阻塞队列有了解过吗?说说看
- 面试官: 阻塞队列的底层实现有了解过吗? 说说看
- 面试官: 同步容器和并发容器有用过吗? 说说看
- 面试官: CopyOnWrite容器有了解过吗? 说说看
- 面试官: Semaphore在项目中有使用过吗?说说看(源码剖析)
- 面试官: Exchanger在项目中有使用过吗?说说看(源码剖析)
- 面试官: CountDownLatch有了解过吗?说说看(源码剖析)
- 面试官: CyclicBarrier有了解过吗?说说看(源码剖析)
- 面试官: Phaser有了解过吗?说说看
- 面试官: Fork/Join 有了解过吗?说说看(含源码分析)
- 面试官: Stream并行流有了解过吗?说说看