【云原生 | Docker篇】实战Dockerfile(五)

2022-05-11 12:54:31 浏览数 (2)

实战Dockerfile

前言

博主语录:一文精讲一个知识点,多了你记不住,一句废话都没有

经典语录:别在生活里找你想要的,要去感受生活里发生的东西

Dockerfile基础知识已经在上一篇做了详细介绍,如果还不是很清楚的同学可以点击传送门再复习一遍。

传送门:【云原生 | Docker篇】深入Dockerfile_Lansonli的博客-CSDN博客

以下是实战经典十例,反复练习,可玩转Dockerfile

运行实例命令

代码语言:javascript复制
# 修改dockerfile文件
vim Docderfile

# 构建容器看执行过程
docker build --no-cache -t demo:test -f Dockerile .

#传入构建参数
docker build --no-cache --build-arg param="11 22 33" msg="aa bb cc" -t demo:test -f Dockerfile2 .


#进入容器控制台
docker exec -it mydemo1 /bin/sh

第一例、这是我第一个Dockerfile

这是我第一个Dockerfile FROM alpine给镜像加个标签 LABEL maintainer="lanson @ dd" abc=def aaa=bbb cccc=ddd 运行的指令,安装了软件,修改了文件,默认是用id=0 也就是root,这个基础系统的root用户代表镜像构建过程中运行的命令。 RUN echo 11111镜像启动如果要运行很长命令才行,容器启动执行的命令1、准备一个sh文件,让镜像启动运行sh文件(大多镜像操作)2、直接在CMD的位置写即可 CMD sleep 10;echo success

第二例、ARG指令和ENV指令简单使用

不可以引用多个 FROM alpine LABEL maintainer="llanson @ dd" abc=def aaa=bbb cccc=ddd #指定构建参数【构建时】 ARG aaa=aaaa #指定环境变量【为RUN以及CMD指定环境变量的】 ENV parm=11111shell* 形式; bash -c "echo 11111" RUN echo $parm exec 形式。$parm 默认拿不到ENV RUN "echo","$aaa"错误语法 RUN "echo",'$parm'错误语法 RUN "echo",$parm错误语法。NOT FOUND(取不出环境变量【ENV】,ARG也是取不出) #RUN "echo",'${aaa}' #RUN "echo",${parm} #都是可以启动容器的命令有什么不同 #CMD sleep 1;echo $parm;echo $aaa;都是可以启动容器的命令有什么不同 ENTRYPOINT sleep 1;echo $parm;

第三例、ARG指令可任意位置定义

#可以在任意位置定义,并在以后取值使用, #使用--build-arg version=3.13 改变;以我们传入的为准 ARG version=3.13.43.13 FROM alpine:$version LABEL maintainer="lanson" a=b c=dd #构建期 运行期都可以生效;但是只能在运行期进行修改 #怎么修改:构建期修改和运行期修改 #构建期不能改 ENV的值 #运行期:docker run -e app=atguigu 就可以修改 ENV app=itdachang ##测试构建期间生效 RUN echo $app RUN echo $param定义以后的剩下环节(不包括运行时)能生效:取值$param; #可以在构建时进行变化,docker buildARG不像ENV不能并排写 ARG param=123456undefined ARG msg="hello docker" #构建时期我们会运行的指令(根据Dockerfile创建一个镜像的整个过程时期) RUN echo 11111 RUN echo $param RUN echo $msg #运行时期我们会运行的指令(根据之前创建的镜像启动一个容器,容器启动默认运行的命令) #(docker run/docker start)CMD和ENTRYPOINT` 都是指定的运行时的指令 CMD "/bin/sh","-c","echo 1111;echo $param;echo app_${app}"

第四例、ENV的坑--构建期间就已经确定好值

env的坑 FROM alpineARG msg=hello# ENV肯定能引用ARGENV name=${msg}RUN echo ${name}RUN echo ${msg}ENV只能运行期改掉 ENV msg1=hello ENV msg2=$msg1以上构建期间就已经确定好值了;ENV持久化问题。 RUN echo ${msg1} RUN echo ${msg2}msg1=msg2没问题;如果我运行期修改了msg1=66666的值,请求msg1;msg2输出什么结果输出: 6666 hello; 传值不是传引用???原因:docker build的时候,env环境的信息会固化,直接在镜像配置里面就已经写死,msg1=hello,msg2=hello。-e 真的只能修改当前env本身为什么运行期间能用ENV定义的所有值,一定是ENV存在某个地方 CMD "/bin/sh","-c","echo ${msg1};echo ${msg2};"

第五例、ADD与COPY指令简单使用

ADD与COPY指令 FROM alpine #把上下文Context指定的内容添加到镜像中,如果是压缩包,自动解压,把当前内容复制到这个 alpine小系统里面如果是远程文件,自动下载;如果是压缩包,自动解压; ADD https://download.redis.io/releases/redis-6.2.1.tar.gz /dest/ #本地linux系统的内容文件添加进去 【宿主机 镜像内】docker build -t demo:test -f Dockerfile 【.:上下文的文件路径】 : .代表上下文环境;代表Dockerfile所在的当前目录 #自动解压压缩包位置:/root/dockerfiles ADD *.tar.gz /app/RUN ls -l相当于给当前容器开一个用户,以后的命令可以用这个用户运行不自动解压和下载COPY nginx以容器的用户:RUN "useradd " COPY --chown=redis:redis *.tar.gz /redis/RUN指令上下并没有上下文关系;RUN cd /dest当前还是列举的根目录RUN ls -l RUN cd /dest && ls -l RUN cd /app && ls -l RUN cd /redis && ls -l #把上下文Context指定的内容复制到镜像中COPY

第六例、COPY的文件可以改变用户

COPY的文件可以改变用户 FROM alpine开用户 #RUN adduser -u lanson -g lanson以后的所有命令会用 lanson:lanson 来执行。有可能没有执行权限容器中的ROOT虽然不是linux宿主机的真实root,但是可以改掉这个镜像的所有 USER 1000:1000把复制来的文件给用户所有权 COPY --chown=lanson:lanson *.txt /a.txt RUN ls -l / #不是root不能写 RUN echo 2222 >> a.txt

第七例、 WORKDIR的应用

WORKDIR的应用 FROM alpine RUN pwd && ls -l为以下所有的命令运行指定了基础目录 WORKDIR /app可以为进入容器指定一个默认目录 WORKDIR abc ##比如我们的nginx镜像可以做成这样 #WORKDIR /usr/share/nginx/html/app/abc 多个WORKDIR可以嵌套 RUN pwd && ls -l #复制到当前目录下 COPY *.txt ./ RUN pwd && ls -l CMD ping baidu.comNginx镜像WORKDIR应用 FROM nginx WORKDIR /usr/share/nginx/html #剩下都是原来 nginx 默认的

第八例、VOLUME需要注意的坑与EXPOSE使用

FROM alpine RUN mkdir /hello && mkdir /app RUN echo 1111 > /hello/a.txt RUN echo 222 > /app/b.txt #挂载 容器的指定文件夹,如果不存在就创建。 #指定了 VOLUME ,即使启动容器没有指定 -v 参数,我们也会自动进行匿名卷挂载容器内的 /hello ,/app 文件夹,请你在使用镜像启动容器的时候,自动给宿主机上挂载VOLUME挂载出去的东西,容器改变也不会最终commit的时候生效-v 使用 VOLUME和-v挂载出去的目录(外面变,容器里面变)。但是所有改变也生效了1)、但是 docker commit 提交当前容器的所有变化为镜像的时候,就会丢弃2)、VOLUME "/hello","/app" 容器以后自动挂载,在Dockerfile中对VOLUME的所有修改都不生效3)、挂载只有一点就是方便在外面修改,或者把外面的东西直接拿过来所以这个写在最后JAVA 日志都要挂外面 /app/logVOLUME "/log" VOLUME "/hello","/app" VOLUME 指定的挂载目录这两句话没有生效 RUN echo 6666 >> /hello/a.txt RUN echo 8888 >> /app/b.txt RUN cd /hello && echo 88888 >>a.txt #暴露 ,这个只是一个声明;给程序员看。docker也能看到docker -d -P(随机分配端口,) EXPOSE 8080 EXPOSE 999 CMD ping baidu.com

第九例、CMD、ENTRYPOINT容器启动指令

FROM alpineENTRYPOINT: 入口(真正的门)ENTRYPOINT "ping" 命令(进门的时候带口令)最终的用法: CMD是给ENTRYPOINT提供参数的 #CMD可以被修改CMD ping baidu.comENTRYPOINT CMD = 容器的完整启动命令这是启动命令ENTRYPOINT ping CMD baidu.com = 错误 #多个CMD只有最后一次生效CMD ping baidu.com"echo","${param}" 不是bash -c的方式,取不出环境变量性 【】echo $param = "/bin/sh","-c","多长的命令都写在这里 echo ${param}"ENTRYPOINT或者CMD作为唯一入口,只能写一个,最后一个生效ENTRYPOINT ping atguigu.comRUN,CMD,ENTRYPOINT[]: "/bin/sh","-c" = shellshell: FROM alpine ENV url=baidu.com #CMD "ping","baidu.com"CMD "useradd","-u","1000","-g","2000"CMD "ping","${url}" 取不出变量CMD ping ${url}官方都是建议使用 []方式CMD "/bin/sh","-c","ping ${url}"ENTRYPOINT ping baidu.com CMD怎么写都没用,容器启动都是以ENTRYPOINT的完整命令为准java -jar xxxx.jar --spring.profile=dev --server.port=8888这两个合在一起不能是错误的命令 #官方推荐的写法,,变化的写CMD,而CMD是提供参数给ENTRYPOINTdocker run imageName cmd1 一旦传递了cmd1,CMD指定的所有参数都会被覆盖,自定义参数的情况下一定要传完 CMD "5","baidu.com" #exec的写法 不变的写 ENTRYPOINT;未来他是容器启动的唯一入口, ENTRYPOINT "ping","-c"

第十例、 多阶段构建

FROM alpine RUN 安装maven RUN mvn clean package COPY xx.jar /app.jar ENTRYPOINT "java","-jar","app.jar" #SpringBoot应用 java -jar xxx.jarjre环境;可以自己打包一个镜像分为多个大的阶段进行构建,最终的构建结果是最后一个阶段的结果多阶段构建FROM alpine AS buildxxxxxxFROM jreCOPY --from=build xxx xxxENTRYPOINT "executable" FROM maven:3.6.1-jdk-8-alpine AS buildapp WORKDIR /app COPY pom.xml . COPY src . RUN mvn clean package -Dmaven.test.skip=true/app 下面有 target RUN pwd && ls -l RUN cp /app/target/*.jar /app.jar RUN ls -l以上第一阶段结束,我们得到了一个 app.jar只要一个JRE FROM openjdk:8-jre-alpine #FROM openjdk:8u282-slim RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone LABEL maintainer="lanson"把上一个阶段的东西复制过来 COPY --from=buildapp /app.jar /app.jardocker run -e JAVA_OPTS="-Xmx512m -Xms33 -" -e PARAMS="--spring.profiles=dev --server.port=8080" -jar /app/app.jar启动java的命令 ENV JAVA_OPTS="" ENV PARAMS="" ENTRYPOINT "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar /app.jar $PARAMS"

十大案例比较经典,里面的备注信息一定看,注意点都在写在注释里,如果对Docker还不是很了解可以回顾看我之前的文章:

大数据需要拥抱云原生吗?云原生为什么这么火?_Lansonli的博客-CSDN博客_云原生大数据

【云原生 | Docker篇】《带你走进Docker的世界》轻松学会原理|架构|安装|加速(一)_Lansonli的博客-CSDN博客

【云原生 | Docker篇】轻松学会 Docker命令(二)_Lansonli的博客-CSDN博客

【云原生 | Docker篇】网络和存储原理_Lansonli的博客-CSDN博客

0 人点赞