摘要

本实验将带你探索如何将运行中的容器保存为新镜像,以及如何使用Dockerfile从头构建镜像。这两种方法都是Docker生态系统中创建自定义镜像的重要技术。

在Docker的世界中,镜像是容器的基础,而自定义镜像则是应用容器化的关键。本实验将介绍两种构建自定义镜像的方法:

  1. 使用docker commit命令将运行中的容器保存为新镜像
  2. 使用Dockerfile文件定义镜像构建过程,并通过docker build命令构建镜像

通过这两种方法,我们可以将应用程序、配置文件和依赖项打包成一个可移植的镜像,便于分发和部署。

准备工作

  1. 删除所有容器
  2. 删除所有镜像
  3. 下载 nginx 镜像

任务一:使用 docker commit 构建

docker commit命令允许我们将运行中容器的当前状态保存为新镜像。这种方法特别适合在容器中进行交互式操作后,将结果保存下来。

基本操作流程是:运行容器 → 修改容器 → 保存修改后的容器

在这个任务中,我们将使用nginx作为基础镜像,部署一个简单的网站,然后将这个定制化的容器保存为新镜像。

1. 运行nginx容器

首先,我们启动一个nginx容器,并进入交互式模式:

docker run -it -p 80:80 --name working nginx sh

运行并进入容器
运行并进入容器

2. 替换原有的网页

删除默认配置网页:

rm /usr/share/nginx/html/index.html

切换到网站根目录并下载网站文件:

cd /usr/share/nginx/html

# 下载网站文件
curl -O "https://git.seahi.me/seahi/docker/raw/branch/main/2.4%E6%9E%84%E5%BB%BA%E9%95%9C%E5%83%8F/index.html"

curl -O  https://git.seahi.me/seahi/docker/raw/branch/main/2.4%E6%9E%84%E5%BB%BA%E9%95%9C%E5%83%8F/styles.css

3. 将容器保存为镜像

按下Ctrl+C停止Nginx服务,然后退出容器:

exit

现在使用docker commit命令将修改后的容器保存为新镜像:

docker commit working mysite:v0.1

现在,我们已经成功地将一个运行中的容器保存为新镜像mysite:v0.1。这个镜像包含了我们部署的网站内容。

4. 运行新镜像

docker run -d -p 8080:80 --name newnginx  mysite:v0.1 nginx -g "daemon off;"

在浏览器中访问服务器IP地址:8080,应该能看到我们部署的网站:

网站页面
网站页面

任务二:通过Dockerfile构建

虽然docker commit方法简单直观,但它缺乏可重复性和透明度。使用Dockerfile构建镜像是更推荐的方法,它提供了清晰的构建步骤文档,便于版本控制和自动化构建。

信息

同学们应该已经发现了,当你做完镜像发现有问题时,往往需要重新制作,非常消耗时间。这是 docker commit 的典型缺点。

在本任务中,你需要为一个简单的问候网站创建Docker镜像。这个网站会显示"Hello from Docker!"并展示访问次数。

1. 准备工作目录和源文件

首先,创建一个新的工作目录并下载网站文件:

mkdir /root/myflask
cd /root/myflask

在该目录下准备两个文件:

app.py

from flask import Flask
import redis

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1

@app.route('/')
def hello():
    count = get_hit_count()
    return f'Hello from Docker! 访问次数: {count}\n'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

requirements.txt

flask==2.3.0
redis==4.5.0

2. 创建Dockerfile

在工作目录中创建一个名为Dockerfile的文件:

vim Dockerfile

按要求编写Dockerfile

要求一:

  • 基础镜像:python:3.9-alpine
  • 工作目录:/app
  • 复制宿主机的 requirements.txt 到容器内的工作目录
  • 安装依赖:pip install --no-cache-dir -r requirements.txt
  • 复制宿主机的 app.py 到容器内的工作目录
  • 暴露端口:5000
  • 启动命令:python app.py

要求二:元数据标签

添加以下标签信息:

  • maintainer - 你的姓名
  • version - 1.0.0
  • project - "myflask"
  • build-date - 当前日期(格式:2024-01-15)

要求三:环境变量

设置以下环境变量:

  • PYTHONUNBUFFERED=1 (Python输出不缓冲)
  • FLASK_APP=app.py
  • FLASK_ENV=production
  • FLASK_HOST=0.0.0.0
  • FLASK_PORT=5000
  • TZ=Asia/Shanghai (设置时区)

3. 构建镜像

使用docker build命令构建镜像:

docker build -t 镜像名 .

参数说明:

  • -t:指定镜像的标签(名称和版本)
  • .:指定构建上下文(当前目录)

两种构建方法的对比

docker commit 对比 Dockerfile

docker commit

  • 优点:简单直观,适合快速原型开发和探索
  • 缺点:构建过程不透明,难以重现,不适合团队协作和自动化

Dockerfile

  • 优点:构建过程透明,易于版本控制,支持自动化,是业界最佳实践
  • 缺点:需要预先规划构建步骤,学习曲线略陡

在实际工作中,Dockerfile 是构建 Docker 镜像的推荐方法,而docker commit通常用于调试和学习过程中。