dockerfile编写学习
0x 01 前言
镜像的定制实际上就是定制每一层所添加的配置文件,如果我们可以把每一层的修改、安装、构建、操作的命令都写入一个脚本,然后用这个脚本来构建、定制镜像,那么镜像构建透明性的问题、体积的问题就会得到解决,这个脚本就是 Dockerfile; Dockerfile 是一个文本文件,其内包含了一条条的指令,每一条指令构建一层,每一层指令的内容,就是描述该层应该如何构建,然后通过 commit 构成新的镜像。
0x 02 Dockerfile 常用参数
FROM
FROM:指定基础镜像,必须是第一条指令,格式为FROM image
或FROM image:tag
1 | # 定制 nginx 镜像的 Dockerfile |
注: Docker Hub 上有很多高质量的服务类的官方镜像可以拿来直接使用,比如:nginx 、redis 、mysql 、php 、mongo \ tomcat 等,可以在其中找最符合的一个进行定制
RUN
RUN :用来执行命令行命令,格式有两种:
shell 格式:
RUN <命令>
,就像直接在命令行中输入的命令一样exec 格式:
RUN ["可执行文件",“参数1”,“参数2”]
,更像是函数调用中的格式
warning:每一个RUN命令都会在 docker镜像中新建一层,所以应该尽量少用 RUN 命令,而且要在RUN 的最后要做必要的清除工作
1 | # 一层构建,并在最后清理压缩包等缓存文件 |
COPY
COPY : 用来从构建上下文目录中<原路径>的文件/目录复制到新一层镜像内的 <目标路径>位置,格式有两种:
1,shell 格式:COPY [--chown=<user>:<group>] <原路径>...<目标路径>
2,exec 合适:COPY[--chown=<user>:<group>] ["原路径1",... "<目标路径>"]
原路径:可以是多个,甚至可以是通配符
目标路径:可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定,不需要事先创建,会自动创建)
1 | # 利用 通配符 进行复制 |
note : COPY 会将原文件的各种数据都保留,比如 读、写、执行权限,可以通过 –chown=
CMD
1 | CMD ["executable", "param1", "param2"], 推荐使用该方式 |
CMD指令的主要目的是为执行容器提供默认值,每个Dockerfile只有一个CMD命令,如果指定了多个CMD命令,也只会有一条执行,如果启动容器的时候指定了运行的命令,则会覆盖掉CMD指定的命令。
EXPOSE
语法:EXPOSE <端口1> [<端口2>...]
该条指令是声明运行时容器提供的服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。这样声明带来两个好处:
1,帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射
2,在运行时使用随机端口映射,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口
note: 要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p 是映射宿主端口和容器端口,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会在宿主进行端口映射。
WORKDIR
格式为:WORKDIR /path/to/workdir
切换⽬录指令,类似于cd命令,对RUN、CMD、ENTRYPOINT⽣效。
1 | WORKDIR /var/www/html |
LABEL
使用LABEL指令,可以为镜像设置元数据,例如镜像创建者或者镜像说明。旧版的 Dockerfile 语法使用MAINTAINER指令指定镜像创建者,但是它已经被弃用了。有时,一些外部程序需要用到镜像的元数据,例如nvidia-docker需要用到com.nvidia.volumes.needed
。示例如下:
1 | FROM node:7-alpine |
ENV
ENV : 用来设置环境变量,格式有两种:
1,ENV
2,ENV
在设置了环境变量之后,无论是后面的其它指令,如 RUN ,还是运行时的应用,都可以直接使用这里定义的环境变量
1 | # 定义环境变量 |
0x 03 构建镜像
1 | docker build -t webprac . |
0x 04 动态flag编写
动态flag的存在形式一般有以下三种:文件中、执行readflag、数据库中
文件
linux下,sed
命令可以将file中每行的字符串进行替换:
1 | sed -i 's/原字符串/新字符串/' file |
export
命令可以查看、设置环境变量
那么在docker-php-entrypoint
文件中写入:
1 | #!/bin/sh |
就会根据当前环境变量的FLAG
值来替换掉flag.php
中的flag_here
,因此还需要在flag.php
中设置:
1 | <?php |
这样,在Dockerfile目录执行docker build -t test .
将Dockerfile文件打包为镜像test
,使用安装了动态靶机插件的CTFd平台部署后,该插件在启动靶机时会自动生成flag并应用到环境变量中,这样便实现了生成动态flag。
readflag
先来看下写法:
1 | #!/usr/bin/env bash |
首先将环境变量$FLAG
写入到/flag
中,之后进行权限配置:
1.chmod u+s /readflag : 为/readflag
文件加上setuid标志,设置使文件在执行阶段具有文件所有者的权限
2.chmod 400 /flag :将flag
文件权限设为文件拥有者只读,群组和其他用户没有任何权限
那么执行./readflag
时,就会拥有文件所有者的权限,可以读取/flag
了
数据库
flag.sh:
1 | #!/bin/bash |
0x 05 打包镜像到Docker Hub
为了方便搜索和下载自己编写的镜像,可以通过以下步骤来实现:
1.到https://hub.docker.com/
注册一个账号
2.登录:
1 | docker login -u 用户名 -p 密码 |
3.更改镜像标签,格式为用户名/标签名
:
1 | docker tag test 用户名/镜像名 |
4.推送:
1 | docker push 用户名/镜像名 |
5.登出:
1 | docker logout |
这时就可以在Docker Hub上找到刚上传的镜像了,将其添加描述后就能使用docker search
搜索到自己的镜像
0x 06 ctfd平台部署
参考这几篇文章:
https://www.zhaoj.in/read-6333.html
https://blog.csdn.net/fjh1997/article/details/100850756
0x 07 docker-compose
docker-compose.yml:告诉docker-compose该怎么编排一组服务
参考链接:
https://www.cnblogs.com/zpcoding/p/11450686.html
https://www.cnblogs.com/fundebug/p/write-excellent-dockerfile.html