DockerFile

一、DockerFile是什么?

DockerFile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本,构建三步骤:

  1. 编写Dockerfile文件
  2. docker build
  3. 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中的指令需要满足如下的规则:

  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  2. 指令按照从上到下,顺序执行
  3. #表示注释
  4. 每条指令都会创建一个新的镜像,并对镜像镜像提交

2.2.docker 执行Dockerfile的流程

docker执行一个Dockerfile脚本的流程大致如下:

  1. docker从基础镜像运行一个容器
  2. 执行一条指令并对容器做出修改
  3. 执行类似docker commit的操作提交一个新的镜像层
  4. docker在基于刚提交的镜像运行一个新容器
  5. 执行dockerfile中的下一条指令直到所有指令都执行完成

2.3.说明

从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,

  • Dockerfile是软件的原材料

  • Docker镜像是软件的交付品

  • Docker容器则可以认为是软件的运行态。

Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

  1. Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
  2. Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
  3. 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被触发

DockerFile命令

BUILDBOTHRUN
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

我们从官方pull下来的centos镜像是mini版的,所以不带有vim、ifconfig这些基础命令,那我们就来自定义一个镜像,功能比官方下载的强大点,同时运用下各个指令。

4.2.1.编写dockerfile

Hub默认Centos镜像什么情况?

自定义mycentos目的使我们自己的镜像具备如下:

  • 登陆后的默认路径
  • vim编辑器
  • 查看网络配置ifconfig支持

首先我们来编写对应的Dockerfile文件。内容如下:

# 指定基础镜像
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 镜像名

执行如下:

在本例中我们用到了 FROM MAINTAINER RUN EXPOSE ENV WORKDIR 命令

4.3.CMD/ENTRYPOINT镜像案例

接下来我们通过案例来看看CMDENTRYPOINT两个命令的区别,这两个命令的作用都是指定一个容器启动时要运行的命令

4.3.1.CMD

Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换掉,我们通过tomcat的案例来介绍。正常情况如下

docker run -it -p 8888:8080 tomcat

执行后,可以成功运行Tomcat

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

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

4.3.2.ENTRYPOINT

有别于CMD命令,ENTRYPOINT命令是在 docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的组合命令。我们通过curl指令来介绍这个案例。Dockerfile文件如下:

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命令,创建容器,如下:

-i参数 查看响应报文头

通过这个例子 可以看到ENTRYPOINT不会覆盖,而是组合成了一个新的命令。

4.4.自定义镜像Tomcat

最后我们通过自定义一个tomcat镜像来介绍下ADDCOPY这两个命令的区别。

4.4.1.创建个tomcat目录

在dockerfile下创建tomcat目录

4.4.2 添加一个文件

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

4.4.3.拷贝相关软件

准备对应的jdktomcat的压缩文件。上传到tomcat目录:

4.4.4.创建Dockerfile文件

创建文件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

4.4.5.构建镜像

执行命令:

docker build -f tomcatfile -t java8/tomcat:8 .

4.4.6.生成容器

构建成功后,我们就可以运行了,命令如下:

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

执行后如下:

4.4.7.生成容器测试访问:

在浏览器输入:http://192.168.42.131:8082,访问如下:这里访问没有内容是因为webappes目录下是空的,但是不影响使用

我们在test目录放入war包,如下:

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

五、虚悬镜像

虚悬镜像:仓库名、标签名都是 <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访问:

posted @ 2023-11-21 18:06  酒剑仙*  阅读(70)  评论(0)    收藏  举报