Lanson

V1

2022/06/15阅读:16主题:丘比特忙

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

实战Dockerfile

前言

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

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

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

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

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

运行实例命令

# 修改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=11111

shell* 形式; 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 aaa;

都是可以启动容器的命令有什么不同

ENTRYPOINT sleep 1;echo $parm;

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

#可以在任意位置定义,并在以后取值使用, #使用--build-arg version=3.13 改变;以我们传入的为准 ARG version=3.13.4

3.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 build

ARG不像ENV不能并排写

ARG param=123456
ARG msg="hello docker"

#构建时期我们会运行的指令(根据Dockerfile创建一个镜像的整个过程时期) RUN echo 11111

RUN echo

msg

#运行时期我们会运行的指令(根据之前创建的镜像启动一个容器,容器启动默认运行的命令) #(docker run/docker start)

CMD和ENTRYPOINT` 都是指定的运行时的指令

CMD ["/bin/sh","-c","echo 1111;echo {app}"]

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

env的坑

FROM alpine

ARG msg=hello

# ENV肯定能引用ARG

ENV name=${msg}

RUN echo ${name}

RUN echo ${msg}

ENV只能运行期改掉

ENV msg1=hello ENV msg2=$msg1

以上构建期间就已经确定好值了;ENV持久化问题。

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 {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.com

Nginx镜像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/log

VOLUME ["/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 alpine

ENTRYPOINT: 入口(真正的门)

ENTRYPOINT [ "ping" ]

命令(进门的时候带口令)

最终的用法: CMD是给ENTRYPOINT提供参数的

#CMD可以被修改

CMD ping baidu.com

ENTRYPOINT + CMD = 容器的完整启动命令

这是启动命令

ENTRYPOINT ping + CMD baidu.com = 错误

#多个CMD只有最后一次生效

CMD ping baidu.com

["echo","${param}"] 不是bash -c的方式,取不出环境变量性 【】

echo {param}"]

ENTRYPOINT或者CMD作为唯一入口,只能写一个,最后一个生效

ENTRYPOINT ping atguigu.com

RUN,CMD,ENTRYPOINT

[]: ["/bin/sh","-c"] = shell

shell:

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是提供参数给ENTRYPOINT

docker 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.jar

jre环境;可以自己打包

一个镜像分为多个大的阶段进行构建,最终的构建结果是最后一个阶段的结果

多阶段构建

FROM alpine AS build

xxxxxx

FROM jre

COPY --from=build xxx xxx

ENTRYPOINT [ "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.jar

docker 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 PARAMS" ]

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

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

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

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

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

分类:

后端

标签:

云计算

作者介绍

Lanson
V1

CSDN大数据领域博客专家