跳转至

利用dockerfile制作镜像

一. 利用现有容器制作镜像

1. 两种利用现有容器制作镜像的方法

第一种: docker export、docker import

第二种: docker commit

2. 区别

a: docker commit要更简单,步骤少

b: 采用docker export制作的镜像没有容器默认运行的指令,无法使用docker run -d 新镜像名:tag运行启动,docker commit可以

3. 利用dockerfile制作镜像

先撰写dockerfile文件

然后使用docker build -t 镜像名:tag -f dockerfile文件/.(当前目录下的dockerfile文件)

二. dockerfile的一些基本概念

Dockerfilie: 由一系列用于根据基础镜像构建的新镜像文件专用指令序列构成

指令: 是指选定基础镜像、按照必要程序、复制配置文件和数据文件、自动运行的服务一级要暴露的端口等

命令: docker bulid

指令行: 由指令和指令参数构成

指令: 其字符不区分大小写。但是约定俗成要使用全大写字符。

注释行: 即#开头的行,必须单独位于某一行中

空白行: 会被忽略

二. dockerfile常用指令

FROM: 指定基础镜像

'作者信息'

CPOY: 将宿主机的文件或目录复制到制作的镜像中

ADD: 将宿主机的文件或目录复制到制作的镜像中

ADD和COPY的区别:

都是复制

COPY的源不支持URL路径但是ADD支持。ADD源为tar.gz/tar.bz2时会自动解压

目标位置不存在时会自动创建

ADD nginx-128.3.tar.gz /usr/local/nginx/ 把nginx-1.28.3.tar.gz解压后的文件放在/usr/local/nginx/目录下

ADD nginx-128.3.tar.gz /usr/local/nginx 把nginx-1.28.3.tar.gz解压后的文件放在/usr/local/目录下,替换nginx目录

ENV: 给镜像设置环境变量

USER: 指定执行命令会运行程序时,使用的用户名或UID号

WORKDIR: 制作镜像时用于切换目录,相当于cd

VOLUME: 卷。镜像中创建一个挂载目录

RUN: docker build时执行的命令

CMD: docker run时运行的命令或程序。docker run时指定运行的内容会将其覆盖掉

ENTRYPOINT: docker run时运行的命令或程序。和CMD同时出现时,CMD指定的内容会成为其参数。docker run时指定运行内容不会将其覆盖掉

EXPOSE: 容器运行时向外暴露的端口。端口/tcp 端口/udp

三. 制作镜像

0. jdk

jdk: java的开发工具

凡是运行java的程序,都必须安装jdk。

开发java程序时候用的jdk版本,部署运行时也必须使用相同版本

比如某个java应用开发使用的版本时jdk-17,在测试或生产环境中也必须使用jdk-17

1. 先做好制作镜像所需的环境

提示: 建议先 docker pull rockylinux:9 把基础镜像拉下来再构建。一来可以避免 docker build 时因网络慢而卡在下载阶段,二来基础镜像独立缓存——就算 docker rmi testnginx:v1.0 删了自定义镜像,rockylinux:9 也不会丢,下次构建直接复用,不用重新下载。

# 先创建用于构建镜像的工作目录
mkdir /root/images
cd /root/images
wget https://download.oracle.com/java/26/latest/jdk-26_linux-x64_bin.rpm
docker pull rockylinux:9
vim dockerfile 

2. 编写dockerfile文件

FROM rockylinux:9
LABEL maintainer='wen@wen.qq.com'
WORKDIR /usr/local
# 下载nginx安装包经常失败,我觉得先在4中下载后再add进入镜像里,省下tar这一步
# ADD  https://nginx.org/download/nginx-1.28.3.tar.gz . 
# ADD 对源来说不能写绝对路径,指定工作目录下的文件,.是指镜像中的WORKDIR目录
ADD nginx-1.28.3.tar.gz  ./
# 编译安装nginx
RUN dnf -y install gcc gcc-c++ zlib zlib-devel openssl openssl-devel pcre pcre-devel && \
    # tar xf nginx-1.28.3.tar.gz && \
    useradd -M -s /sbin/nologin www && \
    cd nginx-1.28.3 && \
    # 在做./这一步之前必须先cd进入目录
    ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module && \
    make && \
    make install && \
    # 清理文件 清理/usr/local/nginx-1.28.3不会导致nginx无法启动
    rm -rf /usr/local/nginx-1.28.3.tar.gz /usr/local/nginx-1.28.3
# 启动 nginx,配合 CMD 最终执行:nginx -g "daemon off;"
# 默认 nginx 会"守护进程化"——主进程启动后 fork 子进程,然后自己退出
# 容器内 PID 1 退出 → 容器结束。daemon off; 强制 nginx 前台运行,PID 1 不退出,容器常驻
ENTRYPOINT ["/usr/local/nginx/sbin/nginx"]
CMD ["-g", "daemon off;"]
# 暴露出80端口,虽然不影响宿主机,但建议写上
EXPOSE 80
# 执行 docker build -t 镜像名:tag -f dockerfile位置 制作镜像
# 执行 docker run -d -p 8080:80 制作时的镜像名:tag 开启镜像

3. 启动镜像,然后查看效果

[root@4 images]# docker build -t myng:v1.1 .
[root@4 images]# docker run -d -p 8080:80 myng:v1.1
[root@4 images]# docker exec -it 384bd42003a6 bash
[root@384bd42003a6 local]# ls
bin  etc  games  include  lib  lib64  libexec  nginx  sbin  share  src
[root@384bd42003a6 local]# curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@384bd42003a6 local]# exit
exit
[root@384bd42003a6 nginx]# curl 192.168.100.102:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

注意:

docker run -d myng:v1.0这条命令中必须要加诸如-p :8080:80指定端口,也可以docker run -d -P myng:v1.0来使用真机随机端口,但后者必须依赖dockerfile文件中的EXPOSE 80否则会导致容器构建了,也能正常运行,但容器外无法访问容器内部。

  1. 如果dockerfile中不加EXPOSE 80,但是docker run -d -p 8080:80 myng:v1.0可以正常访问,宿主机的8080端口,映射虚拟机的80端口

  2. 如果dockerfile中不加EXPOSE 80,但是docker run -d -P myng:v1.0无法访问

  3. 如果dockerfile中加EXPOSE 80,docker run -d myng:v1.0也无法访问

  4. 如果dockerfile中加EXPOSE 80,docker run -d -P myng:v1.0访问宿主机的随机端口,映射虚拟机的80端口

  5. 如果dockerfile中加EXPOSE 80,docker run -d -p 8080:80 myng:v1.0访问宿主机的8080端口,映射虚拟机的80端口

  6. 如果如果dockerfile中加EXPOSE 90,docker run -d -p 8080:80 myng:v1.0此时EXPOSE 90不生效,能否访问真机的8080端口,映射虚拟机的80端口看nginx具体配置

四. 修改镜像

1. 修改访问页面

2. 修改配置文件

3. 修改日志文件与权限

五. 删除容器和镜像

注意顺序:先删容器,再删镜像。 镜像被容器占用时无法删除。

删除单个容器 + 镜像

# -f 强制删除(会先停再删,即使容器在运行)
docker rm -f 容器ID或名称
docker rmi 镜像名:标签

一条命令搞定:

docker rm -f b3c143ce7fbe && docker rmi testnginx:v0.1

批量删除该镜像相关的所有容器 + 镜像

docker rm -f $(docker ps -aq --filter ancestor=testnginx:v0.1) && docker rmi testnginx:v0.1

其他常用清理命令

docker rm 容器ID          # 删除已停止的容器
docker rm -f 容器ID       # 强制删除容器(运行中也删)
docker rmi 镜像ID         # 删除镜像
docker image prune        # 删除所有悬空镜像(无标签的)
docker container prune    # 删除所有已停止的容器
docker system prune -a    # 一键清理:停止的容器、未使用的网络、悬空镜像、未使用的镜像