Docker 镜像的创建(一):https://developer.aliyun.com/article/1525850
八 构建SSH镜像
1,代码展示
cd /opt/sshd vim Dockerfile #第一行必须指明基于的基础镜像 FROM centos:7 #作者信息 MAINTAINER this is ssh image <hmj> #镜像的操作指令 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
2, 搭建ssh 镜像演示
创建ssh 目录
写dockerfile vim Dockerfile
RUN mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh
:
- 作用:确保
/root/.ssh
目录存在,并将其权限设置为只有root用户可读写执行,这是SSH密钥存放的标准安全配置。
生成镜像 docker build -t sshd:centos .
启动容器 docker run -d -P sshd:centos
别的机器 ssh 连接该容器
本机 ssh 连接该容器
九 构建 Systemctl镜像
1,代码展示
mkdir /opt/systemctl cd /opt/systemctl vim Dockerfile FROM sshd:centos MAINTAINER this is systemctl image <hmj> 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 &
2, 搭建systemctl 镜像演示
创建systemctl dockerfile 所在目录
vim Dockerfile
生成镜像
启动容器,并挂载宿主机目录挂载到容器中,和进行初始化
进入容器
使用 systemctl
3, dockerfile 讲解
FROM sshd:centos
:
- 作用:指定基础镜像。这里使用的是一个包含了SSH服务的CentOS镜像,具体名称为
sshd:centos
。
MAINTAINER this is systemctl image
:
- 注释:声明镜像维护者信息,尽管此指令已被Dockerfile最佳实践所废弃,但这里说明该镜像与systemctl配置相关,维护者为hmj。
ENV container docker
:
- 作用:设置环境变量
container
的值为docker
。这可以被应用程序或脚本用来检测是否在Docker环境中运行。
接下来的几行为删除不必要的Systemd单元文件,以精简系统启动过程并避免在Docker容器中不必要的服务启动。
4-11. RUN (cd ...)
到 rm -f /lib/systemd/system/anaconda.target.wants/*;
:
- 作用:这一长行RUN指令包含了一系列的删除操作,目的是清理Systemd的默认启动项,仅保留
systemd-tmpfiles-setup.service
,因为其他服务对于一个主要运行SSH服务的Docker容器来说是多余的。通过这些操作,确保容器启动更快且资源占用更少,同时也避免了不必要的服务干扰。
VOLUME [ "/sys/fs/cgroup" ]
:
- 作用:创建一个数据卷挂载点
/sys/fs/cgroup
。这通常是为了允许Docker容器内的Systemd正确管理其自身的cgroups(控制组),尤其是在尝试在容器内使用Systemd作为初始化系统时非常重要。
#CMD ["/usr/sbin/init"]
:
- 注释:这是一个被注释掉的指令,原本打算用来启动Systemd作为容器的入口点。由于被注释,实际构建的镜像不会执行这一行。如果需要在容器中使用Systemd管理服务,可以取消这一行的注释。
总结来说,这个Dockerfile定制了一个以SSH服务为基础,针对Docker容器优化的Systemd环境。它移除了大量默认的Systemd服务启动链接,减少了容器启动负担,并准备了cgroup的挂载点以便更好地兼容Systemd。最后,虽然没有明确启动命令,但通过取消注释CMD指令或添加适当的ENTRYPOINT/CMD,可以控制容器启动时的行为,比如使用Systemd作为初始化系统。
十 nginx镜像
1, 代码演示
mkdir /opt/nginx cd /opt/nginx/ cp /opt/nginx-1.12.0.tar.gz /opt/nginx vts vim Dockerfile #基于基础镜像 FROM centos:7 #用户信息 MAINTAINER this is nginx image <hmj> #添加环境包 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/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.80.10:32769
2, 演示 搭建 nginx 镜像
创建dockerfile的目录
安装 wgwt 命令
下载 nginx 的安装包
vim Dockerfile
vi run.sh 写运行脚本
启动容器
访问页面
3, dockerfile 详细解释
这是一个 Dockerfile 的内容,用于构建一个基于 CentOS 7 并包含 Nginx 服务器的 Docker 镜像。下面是对每一行指令的详细解释:
- FROM centos:7
- 作用: 指定基础镜像,这里使用的是 CentOS 7 版本。
- MAINTAINER this is nginx image
- 作用: 设置镜像的维护者信息,虽然 Docker 官方推荐使用
LABEL
指令替代此指令,但这里仍然是老式的维护者声明方式,wyq
是维护者的名字或标识。
- RUN yum -y update
- 作用: 更新系统的所有包到最新版,
-y
参数表示自动确认所有安装或更新操作,无需人工干预。
- RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make
- 作用: 安装编译 Nginx 所需的依赖包,包括PCRE库、Zlib库的开发文件、GCC编译器、C++支持以及Make工具。
- RUN useradd -M -s /sbin/nologin nginx
- 作用: 创建一个名为
nginx
的系统用户,-M
表示不创建用户的家目录,-s /sbin/nologin
表示该用户不能登录系统。
- ADD nginx-1.12.0.tar.gz /opt/
- 作用: 将本地的
nginx-1.12.0.tar.gz
文件复制到容器的/opt/
目录下。
- WORKDIR /opt/nginx-1.12.0
- 作用: 设置工作目录为
/opt/nginx-1.12.0
,即解压后的 Nginx 源代码目录。
- RUN ./configure ... && make && make install
- 作用: 配置、编译并安装 Nginx。配置参数包括指定安装路径为
/usr/local/nginx
,设置运行用户和组为nginx
,并启用 HTTP Stub Status 模块以监控状态。
- ENV PATH /usr/local/nginx/sbin:$PATH
- 作用: 设置环境变量
PATH
,将 Nginx 的可执行文件目录/usr/local/nginx/sbin
添加到系统路径中,这样可以在不指定完整路径的情况下直接运行nginx
命令。
- EXPOSE 80
- 作用: 声明容器将在端口 80 上监听,用于 HTTP 服务。
- EXPOSE 443
- 作用: 声明容器将在端口 443 上监听,用于 HTTPS 服务。
- RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
- 作用: 修改 Nginx 配置文件,在最后追加一行
daemon off;
,使得 Nginx 在前台运行,这对于 Docker 容器来说是必要的,因为后台运行的服务会导致容器立即退出。
- ADD run.sh /run.sh
- 作用: 将本地的
run.sh
脚本文件复制到容器的/run.sh
路径下。
- RUN chmod 755 /run.sh
- 作用: 修改
/run.sh
脚本的权限,使其具有执行权限(rwxr-xr-x)。
- CMD ["/run.sh"]
- 作用: 指定容器启动时运行的命令,这里是执行
/run.sh
脚本。
整体来看,这个Dockerfile的目标是创建一个包含Nginx服务的Docker镜像,并配置了一些基本的运行参数,适合于快速部署和管理Nginx服务。不过,需要注意的是,实际构建时应确保 nginx-1.12.0.tar.gz
和 run.sh
文件存在于构建上下文目录中,且版本号 1.12.0
应根据实际情况校验其正确性,因为截至当前知识更新,Nginx并没有明确发布过1.12.0版本。
十一 搭建 tomcat 镜像
1, 代码展示
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 <hmj> 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"] CMD ["/usr/local/tomcat/bin/startup.sh","start"] //创建新镜像 docker build -t tomcat:centos . docker run -d --name tomcat01 -p 1216:8080 tomcat:centos http://192.168.80.10:1216
2, 演示
创建目录
准备 安装包
vim Dockerfile
创建新镜像
启动容器
访问页面
3, dockerfile 详解
这个 Dockerfile 用于构建一个基于 CentOS 7 的 Tomcat 镜像,下面是每行指令的详细说明:
- FROM centos:7
- 作用:指定基础镜像为 CentOS 7,后续的构建步骤将在这个镜像基础上进行。
- MAINTAINER this is tomcat image
- 作用:声明镜像的维护者信息,尽管 Docker 推荐使用
LABEL
指令代替,这里使用了较旧的MAINTAINER
,hmj
是维护者的名字或邮箱。
- ADD jdk-8u291-linux-x64.tar.gz /usr/local/
- 作用:将本地的 JDK 8u291 版本的 Linux x64 安装包添加到容器内的
/usr/local/
目录。
- WORKDIR /usr/local/
- 作用:设置工作目录为
/usr/local/
,后续的命令将在该目录下执行。
- RUN mv jdk1.8.0_291 /usr/local/java
- 作用:将解压后的 JDK 目录重命名为
java
并移动到/usr/local/
下,以便统一管理。
- ENV JAVA_HOME /usr/local/java
- 作用:设置环境变量
JAVA_HOME
指向 JDK 的安装目录。
- ENV JRE_HOME ${JAVA_HOME}/jre
- 作用:设置环境变量
JRE_HOME
指向 JDK 中的 JRE 目录。
- ENV CLASSPATH .:{JAVA_HOME}/lib:JAVAHOME/lib:{JRE_HOME}/lib
- 作用:设置类路径(CLASSPATH),包含了当前目录及 Java 库目录,方便 Java 程序找到所需的类和库文件。
- ENV PATH JAVA_HOME/bin:JAVAHOME/bin:PATH
- 作用:将 JDK 的 bin 目录添加到系统路径中,使
java
,javac
等命令可以直接在终端使用。
- ADD apache-tomcat-8.5.16.tar.gz /usr/local/
- 作用:将 Tomcat 8.5.16 的压缩包添加到
/usr/local/
目录。
- WORKDIR /usr/local/
- 再次设置工作目录为
/usr/local/
,为接下来的命令做准备。
- RUN mv apache-tomcat-8.5.16 /usr/local/tomcat
- 作用:将解压后的 Tomcat 目录重命名为
tomcat
并移动到/usr/local/
下,便于管理。
- EXPOSE 8080
- 作用:声明容器将会监听 8080 端口,这是 Tomcat 默认的 HTTP 端口。
- #CMD ["/usr/local/tomcat/bin/catalina.sh","run"]
- 注释:这行被注释掉了,原本是用来直接运行 Tomcat 的
catalina.sh run
命令,但实际未被采用。
- ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]
- 作用:设置容器启动时执行的命令,这里是直接运行 Tomcat 的
catalina.sh run
,使 Tomcat 作为主进程启动。
- CMD ["/usr/local/tomcat/bin/startup.sh","start"]
- 作用:虽然有了
ENTRYPOINT
,但这里也设置了CMD
。理论上,当ENTRYPOINT
存在时,CMD
会被当作默认参数传递给ENTRYPOINT
。不过,这里的设置可能导致一些混淆,因为通常直接用catalina.sh run
就能启动 Tomcat,不需要再调用startup.sh start
。正确的实践应该是选择ENTRYPOINT
或CMD
其中之一来启动 Tomcat。
综上所述,这个 Dockerfile 主要目的是创建一个包含特定版本 JDK 和 Tomcat 8.5.16 的容器镜像,配置好必要的环境变量和启动命令,以便于运行 Java Web 应用。但最后的 ENTRYPOINT
和 CMD
可能需要根据实际需求调整,避免冲突或冗余。
十二 dockerfile 搭建 mysqld
1, 代码展示
mkdir /opt/mysqld cd /opt/mysqld vim Dockerfile FROM centos:7 MAINTAINER this is mysql image <hmj> RUN yum -y install ncurses ncurses-devel bison cmake pcre-devel zlib-devel gcc gcc-c++ make;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_EXTRA_CHARSETS=all \ -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 -j4;make install ADD my.cnf /etc/my.cnf EXPOSE 3306 RUN chown -R mysql:mysql /usr/local/mysql/;chown mysql:mysql /etc/my.cnf WORKDIR /usr/local/mysql/bin/ RUN ./mysqld \ --initialize-insecure \ --user=mysql \ --basedir=/usr/local/mysql \ --datadir=/usr/local/mysql/data;cp /usr/local/mysql/usr/lib/systemd/system/mysqld.service /usr/lib/systemd/system/;systemctl enable mysqld ENV PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH VOLUME [ "/usr/local/mysql" ] 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.80.10 -u root -P 49153 -pabc123
2, 演示
准备创建目录 和安装包
vim Dockerfile
vim my.cnf
vim run.sh
创建新镜像
3, dockerfile 代码详解
这个 Dockerfile 用于构建一个基于 CentOS 7 的 MySQL 5.7.20 镜像。下面是每一行命令的详细解释:
- FROM centos:7
- 基于 CentOS 7 的官方镜像开始构建。
- MAINTAINER this is mysql image
- 指定镜像的维护者信息,虽然现在推荐使用
LABEL
指令。
- RUN yum -y install ...; useradd -M -s /sbin/nologin mysql
- 安装一系列依赖包,包括ncurses、gcc等开发工具,以及为MySQL用户创建系统账户,不允许登录(-M)且指定shell为nologin。
- ADD mysql-boost-5.7.20.tar.gz /usr/local/src/
- 将MySQL源码包添加到容器的
/usr/local/src/
目录中。
- WORKDIR /usr/local/src/mysql-5.7.20/
- 切换工作目录到MySQL源码解压后的目录。
- RUN cmake ...; make -j4; make install
- 使用cmake配置MySQL编译选项,如安装路径、字符集、存储引擎等,然后并行编译(
-j4
)并安装MySQL。
- ADD my.cnf /etc/my.cnf
- 添加自定义的MySQL配置文件到容器的/etc目录。
- EXPOSE 3306
- 声明容器将在3306端口监听,这是MySQL默认端口。
- RUN chown ...; chown ...
- 更改MySQL数据目录和配置文件的属主和属组为mysql用户。
- WORKDIR /usr/local/mysql/bin/
- 切换工作目录到MySQL的bin目录。
- RUN ./mysqld ...
- 初始化MySQL数据库,不设置root密码(
--initialize-insecure
),指定用户、基目录和数据目录,初始化数据库结构。
- RUN cp ...; systemctl enable mysqld
- 复制MySQL服务单元文件到系统目录,并设置开机启动MySQL服务。
- ENV PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH
- 设置环境变量PATH,使得MySQL的可执行文件路径可以全局访问。
- VOLUME [ "/usr/local/mysql" ]
- 定义数据卷挂载点,允许容器外访问MySQL的数据目录。
- CMD ["/usr/sbin/init"]
- 指定容器启动时运行的命令,这里使用系统初始化脚本,意在使用Systemd管理服务,包括MySQL服务。但注意,在某些Docker环境或场景中,直接使用Systemd可能不适用,可能需要调整为直接启动MySQL服务的命令。
这个Dockerfile展示了从源码编译安装MySQL并进行基本配置的过程,适用于需要高度定制MySQL环境的场景。不过,直接从源码编译可能比直接使用预编译的二进制包更复杂且耗时。
十三 镜像容量过大的解决方案
- 基础镜像尽量使用轻量级最小化的镜像。
- Dockerfile 中尽量把 RUN 指令合并在一起,减少镜像的层数(因为每一个RUN指令就是一个镜像层)。
- 多级构建(拿 Dockerfile 构建好的镜像再构建一次)
十四 总结
1、dockerfile 构建镜像的步骤
先用FROM 指令指定基础镜像
再用MAINTINER 指定维护人信息
然后再用 RUN EXPOSE ADD ENV USER WORKDIR指令编写镜像的过程
最后使用 CMD 或者 ENTPYONT 指令指定启动容器时执行的命令
2、ENTPYONT CMD 区别
容器启动时执行命令的优先级
docker run --entypont=命令 镜像 选项 参数 ---> ENTPYONT ["命令","选顶","参数”] ---> docker run 镜像 命令 选项 参数 ---> CMD ["命令","选项","参数"]
如果在同一个 dockerfile 文件中同时存在 ENTPYONT 和 CMD 时,ENTPYONT 会覆盖 CMD 运行命令,CMD 为提供选项和参数
3、ADD 和 COPY 区别
都可以复制本地文件/目录到镜像中
ADD 可以通过URL路径下 文件并复制到镜像 还可以把本地的tar压缩包进行解压后复制到镜像COPY 支持配合 --from= 选项 实现多个阶段构建
4、如何缩小 dockerfile 构建的镜像体积大小?
仅可能减少指令的数量,比如把 RUN 的 linux 命令进行合并
仅可能的使用最简洁的基础镜像
使用多阶段(多级)构建