【云原生 | Docker篇】实战Dockerfile(五)【与云原生的故事】

举报
Lansonli 发表于 2022/05/10 23:57:16 2022/05/10
【摘要】 ​实战Dockerfile前言博主语录:一文精讲一个知识点,多了你记不住,一句废话都没有经典语录:别在生活里找你想要的,要去感受生活里发生的东西Dockerfile基础知识已经在上一篇做了详细介绍,如果还不是很清楚的同学可以点击传送门再复习一遍。传送门:【云原生 | Docker篇】深入Dockerfile_Lansonli的博客-CSDN博客以下是实战经典十例,反复练习,可玩转Docker...

实战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 $parm;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 $param

RUN echo $msg


 

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

#(docker run/docker start)

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


CMD ["/bin/sh","-c","echo 1111;echo $param;echo app_${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 ${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.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     = ["/bin/sh","-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 $JAVA_OPTS -jar /app.jar $PARAMS" ]

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

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

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

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

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

【与云原生的故事】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/345260

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。