DockerFile
一、DockerFile是什么?
DockerFile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本,构建三步骤:
- 编写Dockerfile文件
- docker build
- docker run
那么DockerFile文件案例如下:
FROM scratch ADD centos-7-x86_64-docker.tar.xz / LABEL \ org.label-schema.schema-version="1.0" \ org.label-schema.name="CentOS Base Image" \ org.label-schema.vendor="CentOS" \ org.label-schema.license="GPLv2" \ org.label-schema.build-date="20201113" \ org.opencontainers.image.title="CentOS Base Image" \ org.opencontainers.image.vendor="CentOS" \ org.opencontainers.image.licenses="GPL-2.0-only" \ org.opencontainers.image.created="2020-11-13 00:00:00+00:00" CMD ["/bin/bash"]
二、DockerFile构建过程解析
2.1.DockerFile内容基础
Dockerfile中的指令需要满足如下的规则:
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像,并对镜像镜像提交
2.2.docker 执行Dockerfile的流程
docker执行一个Dockerfile脚本的流程大致如下:
- docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker在基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
-
Dockerfile是软件的原材料
-
Docker镜像是软件的交付品
-
Docker容器则可以认为是软件的运行态。

- Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
- Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
- Docker容器,容器是直接提供服务的。
三、DockerFile体系结构(保留字指令)
| 说明 | |
|---|---|
| FROM | 基础镜像,当前新镜像是基于哪个镜像的,有继承的意味 |
| MAINTAINER | 镜像维护者的姓名和邮箱地址 |
| RUN | 容器构建时需要运行的命令 |
| EXPOSE | 当前容器对外暴露的端口 |
| WORKDIR | 指定在创建容器后,终端默认登录的进来工作目录,一个落脚点 |
| ENV | 用来在构建镜像过程中设置环境变量 |
| ADD | 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包 |
| COPY | 类似ADD,拷贝文件和目录到镜像中。 将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置 COPY src dest COPY ["src","dest"] |
| VOLUME | 容器数据卷,用于数据保存和持久化工作 |
| CMD | 指定一个容器启动时要运行的命令 Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换 |
| ENTRYPOINT | 指定一个容器启动时要运行的命令 ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及参数 |
| ONBUILD | 当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发 |
| BUILD | BOTH | RUN |
|---|---|---|
| FROM | WORKDIR | CMD |
| MAINTAINER | USER | ENV |
| COPY | EXPOSE | |
| ADD | VOLUME | |
| RUN | ENTRYPOINT | |
| ONBUILD | ||
| .dockerignore |
四、案例演示
4.1.Base镜像(scratch)
Docker Hub 中99%的镜像都是通过在base镜像中安装和配置需要的软件构建处理的,
在dockerhub中搜索Tomcat,地址如下:https://hub.docker.com/,

点击查看镜像构成:

4.2.自定义镜像mycentos

自定义mycentos目的使我们自己的镜像具备如下:
- 登陆后的默认路径
- vim编辑器
- 查看网络配置ifconfig支持
# 指定基础镜像
FROM centos:7
# 镜像维护者的姓名和邮箱地址 MAINTAINER augus<11200297@qq.com>
# 在构建镜像过程中设置环境变量 ENV MYPATH /usr/local
# 指定在创建容器后,终端默认登录的进来工作目录 WORKDIR $MYPATH
# 镜像构建时需要运行的命令 RUN yum -y install vim RUN yum -y install net-tools
# 当前容器对外露出的端口 EXPOSE 80
# 指定一个容器启动时要运行的命令 CMD echo $MYPATH CMD echo "success--------------ok" CMD /bin/bash
操作如下:

4.2.2.构建
语法如下:
docker build -f dockerfile名称 -t 新建的镜像名:TAG .
注意:
- docker build 命令最后有一个 .
- . 表示当前目录,
案例如下:
docker build -f dockerfile2 -t mycentos:100 .
执行后结果

4.2.3.运行
根据之前构建的镜像生成容器,语法如下:
docker run -it 新镜像名字:TAG
执行命令如下:

4.2.4.列出镜像的变更历史
语法如下:
docker history 镜像名
执行如下:

4.3.CMD/ENTRYPOINT镜像案例
Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换掉,我们通过tomcat的案例来介绍。正常情况如下
docker run -it -p 8888:8080 tomcat
执行后,可以成功运行Tomcat

但是当我们在 执行命令后添加参数的话,如下

原因是我们先看Tomact对应的 Dockerfile文件,最后面是启动Tomcat的,而我们添加参数后,就将下面的命令给覆盖了,所以容器无法运行(就相当于有了多个CMD)。

ENTRYPOINT
FROM centos:7 MAINTAINER Augus<Auguses@126.com> ENV MY_PATH /usr/local/ WORKDIR $MY_PATH RUN yum install -y curl EXPOSE 80 ENTRYPOINT [ "curl", "-s", "http://www.baidu.com" ]
构建镜像,如下:
docker build -f dockerfile3 -t myapp .

正常执行run命令,创建容器,如下:


4.4.自定义镜像Tomcat

在当前目录下创建一个 hello.txt文件,作用是COPY

准备对应的jdk和tomcat

创建文件tomcatfile,内容如下:
FROM centos MAINTAINER Augus<Auguses@126.com> # 把主机的hello.txt 拷贝到容器的/usr/local/路径下 COPY hello.txt /usr/local/helloincontainer.txt # 把jdk和tomcat添加到容器中/usr/local ADD jdk-8u172-linux-x64.tar.gz /usr/local ADD apache-tomcat-8.5.43.tar.gz /usr/local # 设置工作访问时候的WORKDIR路径,进入容器的落脚点 ENV MYPATH /usr/local WORKDIR $MYPATH # 配置tomcat和java的环境变量 ENV JAVA_HOME /usr/local/jdk1.8.0_172 ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.43 ENV CATALINA_BASE /usr/local/apache-tomcat-8.5.43 ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin # 容器运行暴露的端口 EXPOSE 8080 # 启动tomcat CMD /usr/local/apache-tomcat-8.5.43/bin/startup.sh && tail -F /usr/local/apache-tomcat-8.5.43/logs/catalina.out
docker build -f tomcatfile -t java8/tomcat:8 .

docker run -d -it -p 8082:8080 --name mytomcat8.5 -v /mydockerfile/tomcat/test:/usr/local/apache-tomcat-8.5.43/webapps/ -v /mydockerfile/tomcat/tomcatlogs/:/usr/local/apache-tomcat-8.5.43/logs --privileged=true 镜像ID
执行后如下:



然后在浏览器访问,如下:

五、虚悬镜像
虚悬镜像:仓库名、标签名都是 <none>的镜像,称为 dangling images(虚悬镜像)。
在构建或者删除镜像时可能由于一些错误导致出现虚悬镜像。例如:
1)在myfile目录下创建Dockerfile内容如下:
FROM centos CMD echo "action is success"
2)构建镜像
# 构建时候没有镜像名、tag
docker build .
3)列出docker中的虚悬镜像:
docker image ls -f dangling=true
4)虚悬镜像一般是因为一些错误而出现的,没有存在价值,可以删除:
# 删除所有的虚悬镜像
docker image prune

六、Dockerfile基于centos7定制java8容器
需要在容器中安装java8,同时安装vim,在myfile中上传文件如下:

编写dockerfile如下:
FROM centos:7 MAINTAINER Augus<Auguses@126.com> # 设置工作访问时候的WORKDIR路径,进入容器的落脚点 ENV MYPATH /usr/local WORKDIR $MYPATH # 安装vim编辑器 RUN yum -y install vim # 安装java8及lib库 RUN yum -y install glibc.i686 RUN mkdir /usr/local/java # 把jdk和tomcat添加到容器中/usr/local/java,注意Dockerfile和安装包必须在同一个位置 ADD jdk-8u172-linux-x64.tar.gz /usr/local/java # 配置tomcat和java的环境变量 ENV JAVA_HOME /usr/local/java/jdk1.8.0_172 ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH ENV PATH $JAVA_HOME/bin:$PATH EXPOSE 80 CMD echo $MYPATH CMD echo "success------------ok" CMD /bin/bash
构建镜像如下:
docker build -f Dockerfile1 -t openjdk:8-oracle .
七、Docker发布微服务
7.1.创建springboot项目
搭建一个简单的SpringBoot项目,在pom.xml中导入依赖:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.augus</groupId> <artifactId>springboot_docker</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot_docker</name> <description>springboot_docker</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.3.12.RELEASE</spring-boot.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <configuration> <mainClass>com.augus.SpringbootDockerApplication</mainClass> <fork>true</fork> </configuration> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
在application.yaml中指定端口
server: port: 6001
在controller包中创建OrderController,如下:
@RestController public class OrderController { @Value("${server.port}") private String port; @RequestMapping("/order/docker") public String helloDocker(){ return "hello world \t" + port + "\t" + UUID.randomUUID().toString(); } @RequestMapping("/order/index") public String index(){ return "服务端口号:" + "\t" + port + "\t" + UUID.randomUUID().toString(); } }
启动项目,然后在浏览器访问

在Idea中运行没有问题时,将其使用maven的package打成jar包。操作如下:

7.2.发布微服务项目到Docker容器
7.2.1.将jdk和jar上传到Linux服务器的myfile目录
上传后结果如下:

7.2.2.编写dockerfile
利用基础镜像java:8构建,在Dockerfile内容如下:
# 基础镜像利用java:8完成 FROM java:8 # 作者 MAINTAINER Augus<Auguses@126.com> #VoLUME指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp VOLUME /tmp #将jar包添加到容器中并更名为augus_docker.jar ADD springboot_docker-0.0.1-SNAPSHOT.jar augus_docker.jar #运行jar包 RUN bash -c 'touch /augus_docker.jar' ENTRYPOINT ["java","-jar", "/augus_docker.jar"] #暴露6001端口作为微服务 EXPOSE 6001
7.2.3.构建镜像
执行如下命令
docker build -f Dockerfile -t springboot_docker:1.0 .
执行如下:

7.2.4.利用镜像创建容器
docker run -d -p 6001:6001 --name springboot springboot_docker:1.0
执行后如下:

7.2.5.测试
在浏览器访问:使用主机ip和端口6001访问:


浙公网安备 33010602011771号