天天看点

dockerfile详解_运维篇DK04Dockerfile详解

dockerfile详解_运维篇DK04Dockerfile详解

Dockerfile-详解

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

dockerfile详解_运维篇DK04Dockerfile详解

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

分享目的:

•为什么使用Dockerfile

•Dockerfile的常用语法

• 官网的MySQL的Dockerfile解析

一.为什么使用Dockerfile

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

•移植性

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

  •安全性

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

  •维护性

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

dockerfile详解_运维篇DK04Dockerfile详解

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

二.Dockfile的语法

2.1 FROM

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

如上图的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 .

dockerfile详解_运维篇DK04Dockerfile详解

3.启动容器

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

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

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

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

dockerfile详解_运维篇DK04Dockerfile详解

5.查看该容器的IP

docker exec -it demo1 ifconfig

dockerfile详解_运维篇DK04Dockerfile详解

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

dockerfile详解_运维篇DK04Dockerfile详解

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可以看到此时端口已经通了.

dockerfile详解_运维篇DK04Dockerfile详解

总结

•expose的作用仅仅是为了声明该容器提供服务的端口有哪些,方便使用者通过

docker run -p

进行端口映射.•如果想随机映射到宿主机的端口,可以使用

docker run -P

2.7.2 VOLUME

•docker 为我们提供了三种不同的方式将数据挂载到容器中:data volume、bind mount、

tmpfs

.这样容器销毁或者退出,数据都不会丢失.

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

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

dockerfile详解_运维篇DK04Dockerfile详解

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

.看到宿主机已经挂载上了该数据.

dockerfile详解_运维篇DK04Dockerfile详解

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

docker rm -f demo3docker run -d --rm --name demo4 -v 6374ab509553b368be41cc5b5cb5534b8f64dae34e48fe969b386bb3c8969c37:/home  demo:vol /bin/sh -c "sleep 800"
           
dockerfile详解_运维篇DK04Dockerfile详解

查看该容器的/home目录

docker exec -it demo4 ls /home

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

dockerfile详解_运维篇DK04Dockerfile详解

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

如下图演示的过程.我们还可以通过

docker volume inspect my_home

.查看这个卷具所在的宿主机位置.

dockerfile详解_运维篇DK04Dockerfile详解

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 .

运行容器

dockerfile详解_运维篇DK04Dockerfile详解

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

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

dockerfile详解_运维篇DK04Dockerfile详解

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的服务端后台进程.

dockerfile详解_运维篇DK04Dockerfile详解