什么是 Dockerfile?
Dockerfile 是用来构建 Docker 镜像的构建文件, 是由一系列的命令和参数构成的脚本
通过指令的方式构建镜像
Dockerfile 主体内容分为四部分:基础镜像信息、 维护者信息、 镜像操作指令和容器启动时执行指令。
构建Dockerfile步骤
编写 Dockerfile 文件
docker built 构建镜像
docker run 创建容器
Dockfile 文件的注意事项
Docker 以从上到下的顺序运行 Dockerfile 的指令。为了指定基本映像,第一条指令必须是 FROM。
每条保留字指令都必须是大写字母, 并且后面要跟随至少一个参数
指令按照从上到下的顺序执行
每条指令可用 # 添加注释
每条指令都会创建一个新镜像层, 并对镜像进行提交
dockerfile的保留字指令
主要保留指令:
指令含义:
FROM
指定基础镜像,必须为第一个命令
格式:
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
示例:FROM mysql:5.6 注: tag或digest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像
MAINTAINER
维护者信息
格式: MAINTAINER <name>
示例: MAINTAINER bertwu MAINTAINER xxx@163.com MAINTAINER bertwu <xxx@163.com>
RUN
构建镜像docker build时执行的命令
RUN用于在构建镜像时执行命令,其有以下两种命令执行方式:
shell执行
格式:
RUN <command>
exec执行
格式:
RUN ["executable", "param1", "param2"]
示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]
注:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,
可以在构建时指定--no-cache参数,如:docker build --no-cache
ADD
将本地文件添加到容器中,tar 类型文件会自动解压(网络压缩资源不会被解压)
格式:
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/
COPY
功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
CMD
在docker run时会执行的命令,如果存在多个则仅最后一个生效。
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
示例:
CMD echo "This is a test." | wc -l
CMD ["/usr/bin/wc","--help"]
注:CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
ENTRYPOINT
配置容器,使其可执行化。配合CMD可省去"application",只使用参数。
格式:
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
ENTRYPOINT command param1 param2 (shell内部命令)
示例:
FROM ubuntu
ENTRYPOINT ["ls", "/usr/local"]
CMD ["/usr/local/tomcat"]
之后,docker run 传递的参数,都会先覆盖cmd,然后由cmd 传递给entrypoint ,做到灵活应用
注:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,
而docker run命令中指定的任何参数,都会被当做参数再次传递给CMD。
Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,
而只执行最后的ENTRYPOINT指令。
通常情况下, ENTRYPOINT 与CMD一起使用,ENTRYPOINT 写默认命令,
LABEL
用于为镜像添加元数据
格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
注:
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据
之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像
ENV
设置环境变量
格式:
ENV <key> <value> #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
ENV <key>=<value> ... #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
示例:
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat=fluffy
EXPOSE
指定于外界交互的端口
格式:
EXPOSE <port> [<port>...]
示例:
EXPOSE 80 443
EXPOSE 8080
EXPOSE 11211/tcp 11211/udp
注: EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
如果没有暴露端口,后期也可以通过-p 8080:80方式映射端口,但是不能通过-P形式映射
VOLUME
用于指定持久化目录
格式:
VOLUME ["/path/to/dir"]
示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1 卷可以容器间共享和重用
2 容器并不一定要和其它容器共享卷
3 修改卷后会立即生效
4 对卷的修改不会对镜像产生影响
5 卷会一直存在,直到没有任何容器在使用它
WORKDIR
工作目录,类似于cd命令
格式:
WORKDIR /path/to/workdir
示例:
WORKDIR /a (这时工作目录为/a)
WORKDIR b (这时工作目录为/a/b)
WORKDIR c (这时工作目录为/a/b/c)
注:
通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY
等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录
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参数来覆盖所指定的用户。
ARG
用于指定传递给构建运行时的变量(给dockerfile传参),相当于构建镜像时可以在外部为里面传参
格式:
<name>[=<default value>]
示例: ARG site ARG build_user=www
ONBUILD
用于设置镜像触发器
格式:
ONBUILD [INSTRUCTION]
示例:
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
注:
NNBUID后面跟指令,当当前的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发
为什么要使用Dockerfile
问题:在dockerhub中官方提供很多镜像已经能满足我们的所有服务了,为什么还需要自定义镜像
核心作用:日后用户可以将自己应用打包成镜像,这样就可以让我们应用进行容器运行.还可以对官方镜像做扩展,以打包成我们生产应用的镜像。
实验:
mkdir /opt/sshd
cd /opt/sshd
vim Dockerfile
#第一行必须指明基于的基础镜像
FROM centos:7
#作者信息
MAINTAINER this is ssh image <wl>
#镜像的操作指令
RUN yum -y update
RUN yum -y install openssh* net-tools lsof telnet passwd
RUN echo 'abc1234' | passwd --stdin root
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config #不使用PAM认证
RUN sed -ri '/^session\s+required\s+pam_loginuid.so/ s/^/#/' /etc/pam.d/sshd #取消pam限制
RUN ssh-keygen -t rsa -A #生成密钥认证文件
RUN mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh
EXPOSE 22
CMD ["/usr/sbin/sshd" , "-D"] #/usr/sbin/sshd -D 用于前台启动sshd服务
//生成镜像
docker build -t sshd:centos .
//启动容器并修改root密码
docker run -d -P sshd:centos
docker ps -a
ssh localhost -p 49155
---------------------Systemctl镜像-------------------------------------
mkdir /opt/systemctl
cd /opt/systemctl
vim Dockerfile
FROM sshd:centos
MAINTAINER this is systemctl image <wl>
ENV container docker
#除了systemd-tmpfiles-setup.service,删除其它所有文件
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*; \
rm -f /etc/systemd/system/*.wants/*; \
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
#CMD ["/usr/sbin/init"]
//生成镜像
docker build -t systemd:centos .
//启动容器,并挂载宿主机目录挂载到容器中,和进行初始化
docker run --privileged -d -P -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd:centos /sbin/init
#--privileged:使container内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限。
docker ps -a
//进入容器
docker exec -it a0d624d2bfa9 bash
systemctl status sshd
方法二:
docker run --privileged -it -P -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd:centos /sbin/init &
----------------nginx镜像------------------------------
mkdir /opt/nginx
cd /opt/nginx/
cp /opt/nginx-1.12.0.tar.gz /opt/nginx
vim Dockerfile
#基于基础镜像
FROM centos:7
#用户信息
MAINTAINER this is nginx image <wl>
#添加环境包
RUN yum -y update
RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make
RUN useradd -M -s /sbin/nologin nginx
#上传nginx软件压缩包,并解压
ADD nginx-1.12.0.tar.gz /opt/
#指定工作目录
WORKDIR /opt/nginx-1.12.0
RUN ./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_stub_status_module && make && make install
ENV PATH /usr/local/nginx/sbin:$PATH
#指定http和https端口
EXPOSE 80
EXPOSE 443
RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf #关闭 nginx 在后台运行
#添加宿主机中run.sh到容器中
ADD run.sh /run.sh
RUN chmod 755 /run.sh
CMD ["/run.sh"]
#CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
vim run.sh
#!/bin/bash
/usr/local/nginx/sbin/nginx
//创建新镜像
docker build -t nginx:centos .
docker run -d -P nginx:centos
docker ps -a
5df9e4383b96 nginx:centos "/run.sh" 15 seconds ago Up 15 seconds 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp silly_davinci
http://192.168.100.10:32769
------------------tomcat 镜像---------------------------
mkdir /opt/tomcat
cd /opt/tomcat
cp /opt/jdk-8u91-linux-x64.tar.gz /opt/tomcat
cp /opt/apache-tomcat-8.5.16.tar.gz /opt/tomcat
vim Dockerfile
FROM centos:7
MAINTAINER this is tomcat image <wl>
ADD jdk-8u91-linux-x64.tar.gz /usr/local/
WORKDIR /usr/local/
RUN mv jdk1.8.0_91 /usr/local/java
ENV JAVA_HOME /usr/local/java
ENV JRE_HOME ${JAVA_HOME}/jre
ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib
ENV PATH $JAVA_HOME/bin:$PATH
ADD apache-tomcat-8.5.16.tar.gz /usr/local/
WORKDIR /usr/local/
RUN mv apache-tomcat-8.5.16 /usr/local/tomcat
EXPOSE 8080
#CMD ["/usr/local/tomcat/bin/catalina.sh","run"]
ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]
//创建新镜像
docker build -t tomcat:centos .
docker run -d --name tomcat01 -p 1216:8080 tomcat:centos
http://192.168.10010:1216
----------------------------mysql镜像------------------------------------
mkdir /opt/mysqld
cd /opt/mysqld
vim Dockerfile
FROM centos:7
MAINTAINER this is mysql image <wl>
RUN yum -y install gcc gcc-c++ ncurses ncurses-devel bison cmake make
RUN useradd -M -s /sbin/nologin mysql
ADD mysql-boost-5.7.20.tar.gz /usr/local/src/
WORKDIR /usr/local/src/mysql-5.7.20/
RUN cmake \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock \
-DSYSCONFDIR=/etc \
-DSYSTEMD_PID_DIR=/usr/local/mysql \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_ARCHIVE_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_PERFSCHEMA_STORAGE_ENGINE=1 \
-DMYSQL_DATADIR=/usr/local/mysql/data \
-DWITH_BOOST=boost \
-DWITH_SYSTEMD=1 && make && make install
RUN chown -R mysql:mysql /usr/local/mysql/
RUN rm -rf /etc/my.cnf
ADD my.cnf /etc/
RUN chown mysql:mysql /etc/my.cnf
ENV PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH
WORKDIR /usr/local/mysql/
RUN bin/mysqld \
--initialize-insecure \
--user=mysql \
--basedir=/usr/local/mysql \
--datadir=/usr/local/mysql/data
RUN cp /usr/local/mysql/usr/lib/systemd/system/mysqld.service /usr/lib/systemd/system/
EXPOSE 3306
ADD run.sh /usr/local/src
RUN chmod 755 /usr/local/src/run.sh
RUN sh /usr/local/src/run.sh
#CMD ["/usr/sbin/init"]
vim my.cnf
[client]
port = 3306
default-character-set=utf8
socket = /usr/local/mysql/mysql.sock
[mysql]
port = 3306
default-character-set=utf8
socket = /usr/local/mysql/mysql.sock
[mysqld]
user = mysql
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
port = 3306
character_set_server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket = /usr/local/mysql/mysql.sock
server-id = 1
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES
vim run.sh
#!/bin/bash
/usr/local/mysql/bin/mysqld
systemctl enable mysqld
//创建新镜像
docker build -t mysql:centos .
//启动容器,并进行初始化
docker run --name=mysql_server -d -P --privileged mysql:centos /usr/sbin/init
//进容器给权限
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f9a4d8f6c65f mysql:centos "/usr/sbin/init" 17 seconds ago Up 16 seconds 0.0.0.0:49153->3306/tcp mysql_server
//进入容器,授权远程连接 mysql
docker exec -it f9a4d8f6c65f /bin/bash
mysql -u root -p
grant all privileges on *.* to 'root'@'%' identified by 'abc123';
grant all privileges on *.* to 'root'@'localhost' identified by 'abc123';
flush privileges;
//在客户端连接mysql容器
mysql -h 192.168.100.10 -u root -P 49153 -pabc123
————————————————
本文为CSDN博主「淘小欣」的原创文章
原文链接:https://blog.csdn.net/weixin_44621343/article/details/115512659