• Dockerfile


    一、什么是dockerfile?

    Dockerfile是一个包含用于组合映像的命令的文本文档。可以使用在命令行中调用任何命令。 Docker通过读取Dockerfile中的指令自动生成映像。

    docker build命令用于从Dockerfile构建映像。

    #规范:
    	Dockerfile命名D必须大写其他必须小写。
    	Dockerfile中所有的指令必须大写
    			
    #构建镜像的命令:
       docker build [OPTIONS] PATH 
    #参数:
    	-t name:tag : 指定构建镜像的名称
    
    docker build -t nginx:v2 .    # . 当前目录
    
    

    二、Dockerfile的基本结构

    Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,# 为 Dockerfile 中的注释。

    一张图解释常用指令的意义:

    img

    三、Dockerfile文件说明

    Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,第一条指令必须是FROM。一个声明以字符开头则被视为注释。可以在Docker文件中使用RUNCMDFROMEXPOSEENV等指令。

    在这里列出了一些常用的指令。

    1.FROM:指定基础镜像,必须为第一个命令

    #格式:
    FROM <image>
    FROM <image>:<tag>
    FROM <image>@<digest>
    
    #示例: 
    FROM mysql:5.6
    
    #注:tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
      
    

    2.MAINTAINER: 维护者信息

    #格式:
    MAINTAINER <name>
    
    #示例:
    MAINTAINER Jasper Xu
    MAINTAINER sorex@163.com
    MAINTAINER Jasper Xu <sorex@163.com>
        
    

    3.RUN:构建镜像时执行的命令

    #RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:
    shell执行
    
    #格式:
    RUN <command>
     
    #示例:
    [root@docker /etc/docker]# cat > Dockerfile << EOF
    FROM nginx:1.21.1
    RUN touch /usr/share/nginx/1.txt
    EOF
    
    [root@docker /etc/docker]# docker build -t nginx:v3 .
    
    [root@docker /etc/docker]# docker run -it --rm nginx:v3 bash
    root@8fee06507b90:/# ls /usr/share/nginx/
    1.txt  html
    
    #注:运行的命令必须是基础镜像中包含的命令,执行的结果直接保存在景象中
    
    

    4.ADD

    #格式:
    ADD <src>... <dest>
    ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
    
    #示例:
    ADD hom* /mydir/          # 添加所有以"hom"开头的文件
    ADD hom?.txt /mydir/      # ? 替代一个单字符,例如:"home.txt"
    ADD test relativeDir/     # 添加 "test" 到 `WORKDIR`/relativeDir/
    ADD test /absoluteDir/    # 添加 "test" 到 /absoluteDir/
        
    

    5.COPY

    #功能描述:复制文件到镜像中
    #语法:
    COPY < src>… < dest>|[“< src>”,… “< dest>”]
    
    #提示:指令逻辑和ADD十分相似,同样Docker Daemon会从编译目录寻找文件或目录,dest为镜像中的绝对路径或者相对于WORKDIR的路径
    
    #示例1:
    [root@docker /etc/docker]# ll
    -rw-r--r--. 1 root root  67 Oct 22 14:44 daemon.json
    -rw-r--r--. 1 root root 101 Nov 11 19:55 Dockerfile
    -rw-r--r--. 1 root root 167 Nov 11 19:49 docker.tar.gz
    -rw-------. 1 root root 244 Oct 22 14:44 key.json
    [root@docker /etc/docker]# cat Dockerfile 
    FROM nginx:1.21.1
    RUN touch /usr/share/nginx/1.txt
    ADD docker.tar.gz /opt
    COPY docker.tar.gz /tmp
    
    
    [root@docker /etc/docker]# docker build -t nginx:v2 .
    [root@docker /etc/docker]# docker run -it --rm nginx:v2 bash
    root@7034bec837ab:/# ls -l /opt
    total 4
    -rw-r--r--. 1 root root 52 Nov 11 11:31 Dockerfile
    root@7034bec837ab:/# ls -l /tmp
    total 4
    -rw-r--r--. 1 root root 167 Nov 11 11:49 docker.tar.gz
    
    # ADD 支持自动解压功能,COPY 不支持
    # ADD 支持通过URL下载文件(不会自动解压文件),COPY 不支持
    
    #示例2:
    [root@docker /etc/docker]# cat Dockerfile 
    FROM nginx:1.21.1
    
    ADD https://mirrors.aliyun.com/centos/7.9.2009/extras/x86_64/Packages/etcd-3.2.28-1.el7_8.x86_64.rpm?spm=a2c6h.13651111.0.0.10bd2f70pV7Kl6&file=etcd-3.2.28-1.el7_8.x86_64.rpm /opt
    
    COPY https://mirrors.aliyun.com/centos/7.9.2009/extras/x86_64/Packages/etcd-3.2.28-1.el7_8.x86_64.rpm?spm=a2c6h.13651111.0.0.10bd2f70pV7Kl6&file=etcd-3.2.28-1.el7_8.x86_64.rpm /tmp
    
    
    [root@docker /etc/docker]# docker build -t nginx:v4 .
    -- --- ----- 省略 ------ ------- --------
     ---> 886df84dcc0d
    Step 6/6 : COPY https://mirrors.aliyun.com/centos/7.9.2009/extras/x86_64/Packages/etcd-3.2.28-1.el7_8.x86_64.rpm?spm=a2c6h.13651111.0.0.10bd2f70pV7Kl6&file=etcd-3.2.28-1.el7_8.x86_64.rpm /tmp
    COPY failed: source can't be a URL for COPY
    
    

    6.CMD:构建容器后调用,也就是在容器启动时才进行调用

    # exec格式:
    CMD ["executable","param1","param2"] (执行可执行文件,优先)
    
    # shell 格式:
    CMD ["param1","param2"] 
    
    #示例1:
    [root@docker /etc/docker]# cat Dockerfile 
    FROM nginx:1.21.1
    CMD ["nginx","-g","daemon off;"]
    
    [root@docker /etc/docker]# docker build -t nginx:v1 .
    [root@docker /etc/docker]# docker run -d nginx:v1
    54a5e03d4f6f663a5ca40beb4e247d335b95b789bb50218b5c8d14ae401a6bad
    [root@docker /etc/docker]# docker ps
    CONTAINER ID   IMAGE      COMMAND                  CREATED         STATUS         PORTS     NAMES
    54a5e03d4f6f   nginx:v1   "/docker-entrypoint.…"   5 seconds ago   Up 4 seconds   80/tcp    laughing_easley
    
    
    #示例2:
    [root@docker /etc/docker]# cat Dockerfile 
    FROM nginx:1.21.1
    CMD nginx -g 'daemon off;'
    
    [root@docker /etc/docker]# docker build -t nginx:v2 .
    [root@docker /etc/docker]# docker run -d nginx:v2
    [root@docker /etc/docker]# docker ps
    CONTAINER ID   IMAGE      COMMAND                  CREATED         STATUS         PORTS     NAMES
    adce915fa2a1   nginx:v2   "/docker-entrypoint.…"   4 seconds ago   Up 4 seconds   80/tcp    dreamy_wright
    
    
    #注:CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
        
    

    7.ENTRYPOINT:配置容器,使其可执行化。配合CMD可省去"application",只使用参数

    #格式:
    ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
    ENTRYPOINT command param1 param2 (shell内部命令)
    
    #示例:
    FROM centos:7
    ENTRYPOINT ["ping"]
    CMD ["127.0.0.0.1"]
    
    #注:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT。如果ENTPYPOINT与CMD同时存在,则CMD的相关内容会被设置为ENTPYPOINT的参数
    
    

    8.LABEL:用于为镜像添加元数据

    #格式:
    LABEL <key>=<value> <key>=<value> <key>=<value> ...
    
    #示例:
    LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
    
    #注:使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
    

    9.ENV:设置环境变量

    #格式:
    ENV <key> <value>  #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
        
    ENV <key>=<value> ...  #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
    
    #示例:
    ENV myName John Doe
    ENV myDog Rex The Dog
    ENV myCat=fluffy
    

    10.EXPOSE:指定于外界交互的端口

    #格式:
    EXPOSE <port> [<port>...]
    
    #示例:
    EXPOSE 80 443
    EXPOSE 8080    EXPOSE 11211/tcp 11211/udp
    
    #注:EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
        
    

    11.VOLUME:用于指定持久化目录

    #格式:
    VOLUME ["/path/to/dir"]
    
    #示例:
    [root@docker /etc/docker]# cat Dockerfile 
    FROM nginx:1.21.1
    VOLUME /usr/share/nginx
    
    [root@docker /etc/docker]# docker build -t nginx:v1 .
    [root@docker /etc/docker]# docker run -itd nginx:v1 bash
    
    # VOLUME /usr/share/nginx 在 /var/lib/docker/volumes目录下随机映射
    #查看
    [root@docker ~]# docker inspect sleepy_wozniak
    		"Mounts": [
                {
                    "Type": "volume",
                    "Name": "462a95793887840bf134192df56117eb2f4ac88e83d80a4e4a99677bf2a4ab98",
                    "Source": "/var/lib/docker/volumes/462a95793887840bf134192df56117eb2f4ac88e83d80a4e4a99677bf2a4ab98/_data",
                    "Destination": "/usr/share/nginx",
                    "Driver": "local",
                    "Mode": "",
                    "RW": true,
                    "Propagation": ""
                }
    
    
    #参数:
      -v  :指定挂载目录
    
    #将宿主机的/opt/目录挂载到容器中的/usr/share/nginx
    [root@docker /etc/docker]# docker run -itd -v /opt/:/usr/share/nginx nginx:v1 bash
    [root@docker ~]# docker exec -it recursing_dijkstra bash
    root@c587e91b92be:/# ls -l /usr/share/nginx
    total 0
    drwx--x--x. 4 root root 28 Oct 22 06:44 containerd
    drwxr-xr-x. 2 root root  6 Oct 27 06:31 demo
    drwxr-xr-x. 2 root root  6 Oct 25 12:22 html5-mario
    
    #查看
    [root@docker ~]# docker inspect recursing_dijkstra
            "Mounts": [
                {
                    "Type": "bind",
                    "Source": "/opt",
                    "Destination": "/usr/share/nginx",
                    "Mode": "",
                    "RW": true,
                    "Propagation": "rprivate"
                }
            ],
    
    

    12.WORKDIR:工作目录,类似于cd命令

    #设置工作目录,运行应用程序时的起始目录(默认是根目录)
    #格式:
    WORKDIR /path/to/workdir
    
    #示例:
    [root@docker /etc/docker]# cat Dockerfile 
    FROM nginx:1.21.1
    VOLUME /usr/share/nginx
    
    [root@docker /etc/docker]# docker build -t nginx:v1 .
    [root@docker /etc/docker]# docker run -itd --name nginx01 nginx:v1 bash
    [root@docker /etc/docker]# docker exec -it nginx01 bash
    root@44c95ab16ca8:/usr/share/nginx# pwd
    /usr/share/nginx
    
    #注:通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
    
    

    13.USER

    #指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
    
    #格式:
    USER user
    USER user:group
    USER uid
    USER uid:gid
    USER user:gid
    USER uid:group
    
    #示例:
    USER www
    
    #注:使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过`docker run`运行容器时,可以通过-u参数来覆盖所指定的用户。
    
    

    14.ARG:用于指定传递给构建运行时的变量

    #格式:
    ARG <name>[=<default value>]
    
    #示例1:
    [root@docker /etc/docker]# cat Dockerfile 
    FROM centos:7
    ARG PACKAGE=zip
    RUN yum install -y $PACKAGE
    
    [root@docker /etc/docker]# docker build -t nginx:v1 .
    --- ---- 省略 ---- --- -- 
    Installed:
      zip.x86_64 0:3.0-11.el7                                                       
    
    Complete!
    Removing intermediate container 29ccd5414e32
     ---> 4890c73d3959
    Successfully built 4890c73d3959
    Successfully tagged nginx:v1
    
    #示例2:  安装软件自定义
    [root@docker /etc/docker]# cat Dockerfile
    FROM centos:7
    ARG PACKAGE
    RUN yum install -y $PACKAGE
    
    [root@docker /etc/docker]# docker build --build-arg=PACKAGE=zsh -t nginx:v2 .
    ------ ---- 省略 ---- ---- ---
    Installed:
      zsh.x86_64 0:5.0.2-34.el7_8.2                                                 
    
    Complete!
    Removing intermediate container a98ffcee77e9
     ---> eed93606434c
    Successfully built eed93606434c
    Successfully tagged nginx:v2
     
    

    15.ONBUILD:用于设置镜像触发器

    #格式:
    ONBUILD [INSTRUCTION]
    
    #示例:
    [root@docker /etc/docker]# cat Dockerfile
    FROM centos:7
    ONBUILD RUN mkdir /test
    
    [root@docker /etc/docker]# docker build -t nginx:v1 .
    [root@af8cd29dcbb2 /]# ls -l | grep test
    
    
    [root@docker /etc/docker]# cat Dockerfile
    FROM nginx:v1
    RUN mkdir /old
    
    [root@docker /etc/docker]# docker build -t nginx:v2 .
    [root@docker /etc/docker]# docker run -it --rm nginx:v2 bash
    [root@fa9f9b35571b /]# ls -l | grep -E "test|old"
    drwxr-xr-x.   2 root root     6 Nov 12 08:02 old
    drwxr-xr-x.   2 root root     6 Nov 12 08:02 test
    
    #注:ONBUILD后面跟指令,在构建时不会执行。当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被触发
    
    

    四、使用Dockerfile构建部署discuz

    1.构建MySQL镜像

    #下载MySQL二进制包
    #官网二进制包下载地址:https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz
    #因为网络问题,我这里是下载的阿里云镜像站的MySQL二进制包
    [root@docker /etc/docker]# wget https://mirrors.cloud.tencent.com/mysql/downloads/MySQL-5.7/mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz
    
    #创建工作目录
    [root@docker /etc/docker]# mkdir -p /discuz/mysql
    [root@docker /etc/docker]# cd /discuz/mysql
    [root@docker /discuz/mysql]# mv /etc/docker/mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz /discuz/mysql
    
    #配置my.cnf
    [root@docker /discuz/mysql]# cat my.cnf 
    [mysqld]
    user=mysql
    basedir=/usr/local/mysql
    datadir=/usr/local/mysql/data
    port=3306
    socket=/usr/local/mysql/mysql.sock
    character-set-server=utf8mb4
    log-error=/usr/local/mysql/data/mysqld.log
    pid-file=/usr/local/mysql/data/mysqld.pid
    [mysql]
    socket=/usr/local/mysql/mysql.sock
    [client]
    socket=/usr/local/mysql/mysql.sock
    
    #编写脚本
    [root@docker /discuz/mysql]# cat start.sh 
    #!/bin/bash
    if [ ! $MYSQL_ROOT_PASSWORD];then
    	echo "远程root密码必填!!!"
    	exit;
    fi
    
    nohup ./create_user.sh &
    
    /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf
    
    
    [root@docker /discuz/mysql]# cat create_user.sh 
    #!/bin/bash
    while true;do
    
    	/usr/local/mysql/bin/mysql -uroot -p''  -e 'show databases;' &>/dev/null
    	
    	if [ $? -eq 0 ];then
    	
    		/usr/local/mysql/bin/mysql -uroot -p${MYSQL_ROOT_PASSWORD} -h${HOSTNAME}  -e 'show databases;' &>/dev/null
    
    		if [ $? -eq 0 ];then
    			exit
    		fi
    
    		/usr/local/mysql/bin/mysql  -uroot -p'' -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' WITH GRANT OPTION;FLUSH PRIVILEGES;" &>/dev/null
    		
    		exit
    	fi
    
    	sleep 1;
    done
    
    [root@docker /discuz/mysql]# chmod +x create_user.sh
    [root@docker /discuz/mysql]# chmod +x start.sh
    
    #配置构建MySQL的Dockerfile
    [root@docker /discuz/mysql]# cat Dockerfile 
    FROM centos:7
    RUN useradd -M -s /sbin/nologin -r mysql
    RUN yum install -y ncurses-devel libaio-devel gcc gcc-c++ numactl libaio glibc cmake autoconf
    ADD mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz /usr/local/
    RUN ln -s /usr/local/mysql-5.7.36-linux-glibc2.12-x86_64 /usr/local/mysql
    RUN chown -R mysql.mysql /usr/local/mysql/
    RUN mkdir -p /usr/local/mysql/data
    RUN chown -R mysql.mysql /usr/local/mysql
    
    RUN /usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
    
    ADD my.cnf /etc/
    WORKDIR /usr/local/mysql
    EXPOSE 3306
    ADD start.sh /usr/local/mysql
    ADD create_user.sh /usr/local/mysql
    CMD ./start.sh
    
    #构建镜像
    [root@docker /discuz/mysql]# docker build -t mysql:v1 .
    
    #启动mysql容器测试
    [root@docker /discuz/mysql]# docker run -d -P -e MYSQL_ROOT_PASSWORD=123 mysql:v1
    [root@docker /discuz/mysql]# docker ps -a
    CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS          PORTS                         NAMES
    2b580fb4e3bd   mysql:v2       "/bin/sh -c ./start.…"   About a minute ago   Up 41 seconds   0.0.0.0:4053->3306/tcp        interesting_lehmann
    
    [root@docker /discuz/mysql]# docker exec -it 2b580fb4e3bd bash
    [root@3b0f31c3f641 mysql-5.7.36-linux-glibc2.12-x86_64]# ./bin/mysql -uroot -p123 -2b580fb4e3bd
    mysql>
    
    #使用Navicat测试连接
    10.0.0.71:4053
    
    

    2.构建nginx+php镜像

    [root@docker /data]# unzip Discuz_X3.4_SC_UTF8_20210926.zip
    [root@docker /data]# mv upload /discuz/nginx+php/
    
    #构建镜像
    [root@docker /discuz/nginx+php]# cat Dockerfile 
    FROM  centos:7
    RUN useradd -M -s /sbin/nologin -r www
    ADD nginx.repo /etc/yum.repos.d/
    RUN yum install -y nginx
    RUN sed -i 's#user nginx#user www#g' /etc/nginx/nginx.conf
    ADD discuz.conf /etc/nginx/conf.d/
    RUN yum remove php-mysql-5.4 php php-fpm php-common
    RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    RUN rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm
    ADD php.repo /etc/yum.repos.d/
    
    RUN yum install -y php72w php72w-cli php72w-common php72w-devel php72w-embedded php72w-gd php72w-mbstring php72w-pdo php72w-xml php72w-fpm php72w-mysqlnd php72w-opcache php72w-pecl-memcached php72w-pecl-redis php72w-pecl-mongodb
    
    RUN sed -i 's#apache#www#g' /etc/php-fpm.d/www.conf
    EXPOSE 80 443
    CMD php-fpm && nginx -g 'daemon off;'
    
    #启动容器测试
    [root@docker /discuz/nginx+php]# docker run -d -P php-nginx:v1
    [root@docker /discuz/nginx+php]# docker ps
    CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                                         NAMES
    6459eb2c0c5a   php-nginx:v1   "/bin/sh -c 'php-fpm…"   3 seconds ago   Up 2 seconds   0.0.0.0:4052->80/tcp, 0.0.0.0:4051->443/tcp   fervent_robinson
    
    #删除所有测试容器
    [root@docker /discuz/nginx+php]# docker rm -f $(docker ps -aq)
    
    

    3.创建网桥

    #创建dis网桥
    [root@docker /discuz/nginx+php]# docker network create dis
    
    #创建容器
    [root@docker /discuz/nginx+php]# docker run -d --network dis --name mysql -e MYSQL_ROOT_PASSWORD=123 mysql:v1
    
    [root@docker /discuz/nginx+php]# docker run -d --name nginx -p 80:80 --network dis -v /discuz/nginx+php/upload/:/usr/share/nginx/html php-nginx:v1
    
    [root@docker /discuz/nginx+php]# docker ps
    CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                         NAMES
    017a58d6a827   php-nginx:v1   "/bin/sh -c 'php-fpm…"   5 seconds ago        Up 2 seconds        0.0.0.0:80->80/tcp, 443/tcp   nginx
    35c458d7c2d3   mysql:v1       "/bin/sh -c ./start.…"   About a minute ago   Up About a minute   3306/tcp                      mysql
    
    
    #本地hosts配置
    10.0.0.71 linux.discuz.com
    
    #浏览器访问
    linux.discuz.com
    
    
    #文件列表
    [root@docker /discuz]# tree -L 2 -C
    .
    ├── mysql
    │   ├── create_user.sh
    │   ├── Dockerfile
    │   ├── my.cnf
    │   ├── mysql-5.7.36-linux-glibc2.12-x86_64.tar.gz
    │   └── start.sh
    └── nginx+php
        ├── discuz.conf
        ├── Dockerfile
        ├── nginx.repo
        ├── php.repo
        └── upload
    
    
  • 相关阅读:
    js 剪切板应用clipboardData
    正则表达式的与或非
    自定义类型转换器
    struts2类库下载
    通过ajax提交form表单
    面试官:为什么Mysql中Innodb的索引结构采取B+树?
    代码生成器:IDEA 强大的 Live Templates
    深入理解JVM,7种垃圾收集器,看完我跪了
    你能说出多线程中sleep、yield、join的用法及sleep与wait区别?
    Java8中一个极其强悍的新特性,很多人没用过(非常实用)
  • 原文地址:https://www.cnblogs.com/backz/p/15549170.html
Copyright © 2020-2023  润新知