dockerfile详解_运维篇DK04Dockerfile详解

38052b9d6dd18e53881ef5ce1c0fcd6a.png

Dockerfile-详解

作者: weipeng.su 目前就职于携程, 从事大数据开发工作

6bcf9889d92d81e6b4e4416c97e7b62d.png

前面我分享了关于容器、虚拟机、物理机的区别(docker分享与入门), 还介绍了容器里关键的镜像、容器、仓库等Docker的核心概念.容器的发展史(容器的发展历史).虚拟机的搭建(Vagrant搭建虚拟机).本次我们具体聊聊Dockerfile.

分享目的:

•为什么使用Dockerfile

•Dockerfile的常用语法

• 官网的MySQL的Dockerfile解析

一.为什么使用Dockerfile

在docker分享与入门 介绍过关于镜像构建的两种方式,一种是推荐的Dockerfile,一种是进入容器中一步步安装和配置我们想要的环境, 最后在通过docker 提供的docker commit命令,将该容器打包成一个镜像.很多人还是不明白为什么要使用Dockerfile.总结来说有以下几点优势.

移植性

我们通过Dockerfile描述了, 我们的镜像是如何一步步构建的.可以清晰的看到安装了哪些软件,其基于哪个开源镜像构建.如果要将镜像分享给别人, 你可以直接分享Dockerfile就行.Dockerfile就几KB可远远比镜像来得小.更加具备方便的移植和分享.

  •安全性

如果有人不想通过Dockerfile来构建,想直接使用你提供的镜像, 他可以查看你的Dockerfile来确认是否该镜像安全.

  •维护性

如果公司中有人离职, 交接程序.一个Dockerfile就把所有的配置都说得清清楚楚.而不是只给你个镜像,出来问题,你也不知道是不是环境变量的原因,还是程序冲突,版本过久.

bfcb065fef73ea005ddaa983fc4630f6.png

如果还认为Dockerfile不好使,可以自己阅读下官方和流行的开源项目构建的镜像, 都是提供了Dockerfile(比如上图就是MySQL的官方提供的Dockerfile).基于这点和Dockerfile的优势, 我们没有理由不适用Dockerfile.

二.Dockfile的语法

2.1 FROM

•FROM用于Dockerfile最开头,用来描述我们要构建的ImageBaseImage

如上图的MySQL官网构建的是  FROM debian:buster-slim 说明其基于debian这个BaseImage构建的MySQL

2.2 Label

定义了image的元数据信息.比如维护者、版本、这个image的作用.
LABEL maintainer='weipeng.su'LABEL version="1.0"LABEL description="This is ods image"

2.3 RUN(重点)

该命令用于执行,你要在容器里执行各种命令,都可以通过该关键字来描述.比如安装软件、依赖库.每RUN一次都会 产生一个新的层(Layer).所以RUN的最佳实践就是将 多条命令合并成一条,使用&&符号.使用 反斜线换行.
RUN yum update && yum install -y vim \python-devRUN /bin/bash -c 'source $HOME/.bashrc;echo $HOME'

•RUN背后的原理

RUN背后其实会自动创建一个临时容器,然后执行相应的命令,执行完后就会自动执行docker commit命令来生成新的镜像.所以才会导致m每RUN一次,都会产生新的一层(Layer).我们可以通过Docker构建镜像时候的log查看到这一点.

2.4 WORKDIR(重点)

设定当前的工作目录.如果该目录不存在会自动创建.
WORKDIR /testWORKDIR demoRUN pwd   # 输出/test/demo

改变工作目录,不要使用RUN cd, 要知道每RUN一次就会生成新的一个层Layer,无形中镜像会膨胀

2.5 ADD和COPY

这两个关键字作用类似,都是用来 将本地的资源文件、代码添加到指定的容器目录里.唯一区别是,  ADD有附加作用,对于压缩文件,其会自动解压.

•大部分情况下我们使用最多的是COPY.•如果是远程文件,可以使用RUN curl或者RUN wget获取.

2.6 Env(重点)

对于很多程序的部署,我们都需要设置环境变量,比如HADOOP的部署,我们需要设置HADOOP_HOME.Env关键字提供了该功能.
ENV MYSQL_VERSION 5.6RUN apt-get install -y mysql-server= "${MYSQL_VERSION}" \ && rm -rf /var/lib/apt/lists/*

2.7 VOLUME和EXPOSE(重点)

2.7.1 EXPOSE

expose主要 用来声明容器中要对宿主机开放的端口, 是 帮助镜像使用者理解这个镜像服务的守护端口, 以方便配置映射(使用 -p 这是小写的p)

•expose的是一个声明,表示容器将会监听这个端口.所以就算expose了, 端口还是没有启动, 如果要实现宿主机和容器的端口映射得用-p参数•Expose可以配合-P(这是大写的P)参数使用, 实现随机从宿主机挑选一个端口和Expose声明的端口进行映射.

1.编写如下Dockerfile

FROM busyboxEXPOSE 8080

2.编译镜像

docker build -t demo .

d1c258819c305b957e02cf1b83d09c8d.png

3.启动容器

docker run -it -d --rm --name demo1 demo /bin/sh -c "sleep 600;""

•这句话的意思是启动容器,并休眠10分钟,这样是为了让容器跑10分钟后会自动销毁,移除容器.•--name demo1 表示容器启动后就叫demo1. 后一个demo表示的是创建容器依据的demo这个镜像.

4.查看该容器的端口映射.

这时候这个容器启动了,并且监听着其自己的8080端口,但是这是无法被宿主机访问的.

ec8bee0c55458891932c85d2a9af37f1.png

5.查看该容器的IP

docker exec -it demo1 ifconfig

286f8eb2139926d532efa69c57224df7.png

6.看下8080端口有没有映射成功

d8466f3004e0e0db199c277c77871269.png

telnet不通说明8080端口实际上并没有和宿主机的8080映射上.

6.使用-p参数进行端口映射

docker run -d -p 8080:8080 --rm --name demo2 demo /bin/sh -c "sleep 800"

然后telnet 127.0.0.1 8080可以看到此时端口已经通了.

b11c8291f812e4bbca4b85e8e1556bf0.png

总结

•expose的作用仅仅是为了声明该容器提供服务的端口有哪些,方便使用者通过docker run -p进行端口映射.•如果想随机映射到宿主机的端口,可以使用docker run -P

2.7.2 VOLUME

•docker 为我们提供了三种不同的方式将数据挂载到容器中:data volume、bind mount、tmpfs.这样容器销毁或者退出,数据都不会丢失.

    •Data Volume是Docker中数据持久化的最佳方式.

先查看当前宿主机下有哪些VOLUME docker volume ls

0de790781d6801445ad0def03c29efd3.png

1.编写如下Dockerfile

FROM busyboxVOLUME /home

2.构建镜像

docker build -t demo:vol .

3.启动容器

docker run -d --rm --name demo3 demo:vol /bin/sh -c "sleep 800"

4.进入容器的/home目录创建文件

创建完后,可以通过docker volume ls.看到宿主机已经挂载上了该数据.

d305dbd2d45e08ef60511c034cedb1a1.png

5.销毁容器并再次启动一个新容器

docker rm -f demo3docker run -d --rm --name demo4 -v 6374ab509553b368be41cc5b5cb5534b8f64dae34e48fe969b386bb3c8969c37:/home  demo:vol /bin/sh -c "sleep 800"

7efa05b94a04ef98b8fdc70f827c1167.png

查看该容器的/home目录docker exec -it demo4 ls /home

可以发现text.txt文件依然存在.

3928fc92a35822419f69ca6d6593cf7f.png

但是这样挂载存在问题.就是这个卷名特别长.我们可以在容器启动的时候就指定-v my_home:/home.这样就会在宿主机中创建一个叫my_home的卷, 以后就方便管理了.

如下图演示的过程.我们还可以通过docker volume inspect my_home.查看这个卷具所在的宿主机位置.

40467d3fbcb102cd623a53432233e6bf.png

2.8 CMD 和ENTRYPOINT(重点)

这两个关键字主要用于在容器启动后要执行哪些命令,一般用于程序的启动.

2.8.1 Dockerfile里的shell和exec格式

Dockerfile里RUN、CMD、ENTRYPOINT都支持这两种语法格式.

shell格式

RUN apt-get install -y vimCMD echo "hello docker"ENTRYPOINT echo "hello docker"

exec格式

RUN ["apt-get", "install", "-y", "vim"]CMD ["/bin/echo", "hello docker"]ENTRYPOINT ["/bin/echo", "hello/docker"]

区别

编写如下两个Dockerfile,然后构建出这两个镜像.

Dockerfile1

FROM centosENV name DockerENTRYPOINT echo "hello $name"

Dockerfile2

FROM centosENV name DockerENTRYPOINT ["/bin/echo","hello $name"]

构建镜像

docker build -t entrypoint-shell .

docker build -t entrypoint-exec .

运行容器

981ab2e74495c7d47b416c61f033f38c.png

第一个DK能打印出hello Docker.第二个DK打印出hello $name.

原因:  我们用shell格式,相当于是在shell中执行命令,所以其能识别出变量. 如果我们用exec格式, 我们只是执行echo这个程序,而不是在shell中执行echo,所以无法识别环境变量.虽然exec格式默认是无法识别出环境变量, 但是如果我们指定云运行时候是通过shell命令运行.也是可以绕过这个限制.

525fb35ff91bb39e26fe79ce55be3495.png

2.8.2 CMD

CMD所指定运行的命令会在容器启动后执行.但可能会被忽略, 如果在 docker run -it centos:7 /bin/bash后这样指定了启动后运行的/bin/bash就会被覆盖.

2.8.3 ENTRYPOINT

ENTRYPOINT可以保证指定的命令一定会被执行,而不会被外部命令覆盖.所以

•一般用在指定容器启动后一定要运行的后台服务.

三.官网的MySQL Dockerfile解读

FROM debian:buster-slim# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get addedRUN groupadd -r mysql && useradd -r -g mysql mysqlRUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/*# add gosu for easy step-down from root# https://github.com/tianon/gosu/releasesENV GOSU_VERSION 1.12...RUN mkdir /docker-entrypoint-initdb.d...ENV MYSQL_MAJOR 8.0ENV MYSQL_VERSION 8.0.20-1debian10...RUN echo "deb http://repo.mysql.com/apt/debian/ buster mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list...VOLUME /var/lib/mysql# Config filesCOPY config/ /etc/mysql/COPY docker-entrypoint.sh /usr/local/bin/RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compatENTRYPOINT ["docker-entrypoint.sh"]EXPOSE 3306 33060CMD ["mysqld"]
如上是官网的MySQL Dockerfile.

•第一行就是描述基于哪个镜像.•RUN groupadd -r mysql && useradd -r -g mysql mysql 是在创建mysql这个用户组,并且创建mysql用户,将其添加到这个用户组中.•ENV MYSQL_VERSION 8.0.20-1debian10. 设置了MYSQL的版本•VOLUME /var/lib/mysql 该目录是mysql存储数据的目录, 表示将mysql的存储挂载到了宿主机•COPY config/ /etc/mysql/ 由于该Dockerfile是官网提供的,放在了github上, 在这个开源项目里官网已经创建了config这个文件夹用来描述mysql的一些配置.该句意思就是 将这些配置拷贝入宿主机器中的/etc/mysql/目录下•EXPOSE 3306 33060 表示将容器将会通过3306和33060提供服务, 如果想进行端口映射应该选映射到容器的这两个端口•CMD ["mysqld"] 表示容器启动后,就会执行这个mysqld,这是mysql的服务端后台进程.

c6a75dd76488e02d959ca267e7838fd9.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值