写在前面:

本篇简单介绍一下如何入手 Docker,从 创建/拉取 镜像,再到运行和管理容器,还包括导出容器等操作。这里先贴一下官方的文档地址:

Docker DocsDocker Documentation is the official Docker library of resources, manuals, and guides to help you containerize applications.icon-default.png?t=O83Ahttps://docs.docker.com/

一、Docker 介绍

作为一个开源的应用容器引擎,Docker 可以让开发者将应用以及应用的依赖打包到一个可移植的容器中,然后发布到任何安装了 Docker 的服务器上运行。这些容器就像一个个轻量级的虚拟机,但与传统虚拟机相比,Docker 容器更加高效、快速和资源友好。

主要特点:

  1. 轻量级

    Docker 容器共享主机内核,不需要像虚拟机那样模拟完整的操作系统,因此启动速度极快,通常在几秒钟内就能启动。
    占用的资源少,多个容器可以在同一台服务器上高效运行,提高了服务器的利用率。
  2. 可移植性

    由于容器包含了应用及其所有依赖,所以可以在不同的环境中轻松迁移,无论是从开发环境到测试环境,还是从本地服务器到云服务器。
    保证了应用在不同环境中的一致性运行,减少了因环境差异导致的问题。
  3. 高效性

    容器的快速启动和停止特性使得应用的部署和扩展变得非常容易。
    可以根据需求快速创建和销毁容器,实现弹性的资源分配。
  4. 隔离性

    每个容器都有自己独立的文件系统、网络和进程空间,实现了应用之间的隔离。
    一个容器中的问题不会影响到其他容器,提高了系统的稳定性和安全性。

核心组成:

  1. 镜像(Image)

    是一个只读的模板,包含了应用程序及其所有依赖(如库、框架、配置文件等)。
    可以从 Docker 仓库中下载或自己创建镜像,然后基于镜像创建容器。
  2. 容器(Container)

    是由镜像创建的运行实例,是一个独立的运行环境。
    可以对容器进行启动、停止、删除等操作,也可以在容器中运行应用程序。
  3. 仓库(Repository)

    用于存储和分发 Docker 镜像,可以是公共仓库(如 Docker Hub),也可以是私有仓库。
    开发者可以将自己创建的镜像推送到仓库中,以便在不同的环境中使用。

使用场景

  1. 应用部署

    简化了应用的部署过程,提高了部署的效率和可靠性。
    可以快速将应用部署到多台服务器上,实现大规模的应用部署。
  2. 微服务架构

    适合用于构建微服务架构,每个微服务可以运行在一个独立的容器中。
  3. 开发环境一致性

    保证了开发、测试和生产环境的一致性,减少了因环境差异导致的问题。
    开发者可以在本地使用与生产环境相同的容器来进行开发和测试。

二、创建镜像

这里介绍几种常见的创建镜像的方式,大家可以根据自己需求选择。

2.1 从 Docker Hub 拉取镜像

第一步:登录/注册 Docker Hub

如果没有则先去官网(https://hub.docker.com/)注册一个,然后登录即可(Desktop版图形化操作即可,普通的则打开终端输入 “ docker login ”)。

第二步:查找所需的镜像

可以直接在官网去搜索即可,这里写几个常用的镜像:

  1. Alpine:基于轻量级 Linux 操作系统的镜像,体积非常小巧,只有 5MB 左右,提供了一些基本的工具和包,如 bashcurlgcc 等,适合构建轻量级的容器。
  2. Ubuntu:基于 Debian 的 Linux 操作系统,常用版本(LTS):22.04、20.04、18.04;
  3. Nginx:广泛使用的 Web 服务器软件,也可用作反向代理、负载均衡和 HTTP 缓存服务器。结合其他技术如 WordPress 等,可以用于构建高性能的 Web 应用程序。
  4. Redis:基于内存的数据存储系统,常用于实时数据缓存、排名、计数器、分布式会话管理等方面,具有快速、可靠且易于使用的特点,适合构建可扩展的分布式系统。
  5. MySQL:流行的关系数据库管理系统,支持多数据类型、多连接和高性能,是开发人员构建数据库应用程序的常用选择之一。
  6. Node.js:基于 JavaScript 的后端服务器技术,支持高性能、非阻塞 I/O 和事件驱动编程,许多开发者使用它来构建 Node.js 的 Web 应用程序和 Web 服务。
  7. Tomcat:一个流行的 Java Web 应用服务器,用于运行 Java Web 应用程序3。
  8. CentOS:一种常用的 Linux 发行版镜像,提供了稳定的操作系统环境,适合用于各种服务器应用的部署。

第三步:拉取所需镜像

在命令行中输入docker pull [镜像名称]:[标签]

如果不指定标签,默认会拉取 latest(最新)标签的镜像。

例如,要拉取官方的 Ubuntu 镜像,可输入

docker pull ubuntu # 最新版
docker pull ubuntu:22.04 # 特定版

后续:可创建自己的镜像仓库

登录上 Docker Hub,在存储库页面上,选择创建存储库。

将其进行命名,比如<you-username>/my-Privateal-repo,将可见性设置为私有。

配置完自己镜像后,可以上传到仓库。上传镜像之前,先对镜像进行标记:

docker tag my_image:latest <you-username>/my-Privateal-repo

使用 docker push 命令将标记后的镜像上传到私有仓:

docker push <you-username>/my-private-repo

当然,可以在另外机器上或使用 pull 拉取验证镜像。

2.2 用 Dockerfile 创建镜像

Dockerfile 是一个文本文件,包含了一系列指令,用于描述如何构建一个 Docker 镜像。这些指令会按照顺序依次执行,最终生成一个包含特定应用及其依赖的镜像,使用 Dockerfile 创建镜像是一种常见且高效的方式,

常见指令:

  1. FROM:指定基础镜像,它是构建新镜像的起点。例如:FROM ubuntu:22.04
  2. RUN:在镜像构建过程中执行命令。可以用于安装软件包、配置环境等。例如:RUN apt-get update && apt-get install -y python3
  3. COPY 或 ADD:将本地文件或目录复制到镜像中。例如:COPY. /app将当前目录下的所有文件复制到镜像中的/app目录。
  4. WORKDIR:设置工作目录。例如:WORKDIR /app将后续命令的工作目录设置为/app
  5. CMD 或 ENTRYPOINT:指定容器启动时要执行的命令。例如:CMD ["python", "app.py"]表示启动容器时运行python app.py命令。

示例:

先编写一个 app.py 文件:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, Docker!'

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

再创建一个 Dockerfile 文件:

FROM python:3.10

WORKDIR /app

COPY..

RUN pip install flask

EXPOSE 5000

CMD ["python", "app.py"]

上面的 Dockerfile 中,设置了工作目录,拷贝当前目录文件到镜像内,并安装了 Flask 库,暴露容器的 5000 端口,最后在容器启动后运行命令启动程序。

接下来只需要在包含 Dockerfile 和 app.py 文件的目录下,运行构建镜像即可:

docker build -t myflaskapp:latest .

其中 -t 参数指定镜像的名称和标签,最后的 . 表示 Dockerfile 所在的目录。

构建镜像后,启动容器即可:

docker run -p 5000:5000 myflaskapp:latest

这里将容器的 5000 端口映射到主机的 5000 端口,这样就可以在浏览器中访问http://localhost:5000 来查看 Flask 应用的输出。


Dockerfile 的优势:

  1. Dockerfile 本身就是一种文档,它清晰地展示了镜像的构建过程和包含的内容。其他开发人员可以更容易理解和使用这个镜像;
  2. 可以根据具体需求自定义镜像的内容和配置。可以选择不同的基础镜像、安装特定的软件包、设置环境变量等,满足各种复杂的应用场景;
  3. 可以确保每次构建的镜像都是一致的,无论在哪个环境中构建。

存在的不足:

  1. 当构建复杂的镜像时,Dockerfile 可能会变得冗长和复杂,需要合理组织指令和管理依赖关系;
  2. 如果配置中使用了不可信的源或安装了未知的软件包,可能会引入安全风险。需要谨慎选择基础镜像和软件源;
  3. 当基础镜像较大或者需要下载大量的软件包时,构建过程可能会比较耗时,并且依赖于良好的网络连接。

之前我们遇到过,当配置的软件源更新或者网络原因等,导致无法构建甚至版本控制不理想等问题。所以对于相对复杂的镜像环境,还是不建议这样构建,直接传输镜像会更稳定。

2.3 导出的镜像文件直接导入

Docker 支持直接把容器导出成 tar 的压缩文件,然后从这个文件导入镜像,即可完美复刻容器的环境和内容。

1. 找出要导出容器的 名称 或 ID

docker ps # 会列出正在运行的容器
docker ps -a # 会列出所有的容器

2. 导出容器到 .tar 文件

docker export container_name > container.tar

后面的文件名可以自己指定

3. 在目标电脑上导入镜像

docker import container.tar new_image_name:tag

其中 new_image_name 是新镜像的名称,tag 是标签(可选)。


这种方法的好处就是:对于特定状态的容器,可以快速地在不同环境中进行迁移,无需重新构建镜像。如果目标环境没有网络连接或者网络受限,这种方式可以避免从远程仓库拉取镜像的问题。

当然,与使用 Dockerfile 构建的镜像不同,通过这种方式导入的镜像没有构建历史记录。这可能会在一些需要追踪构建过程或进行调试的情况下带来不便。

三、运行和管理容器

3.1 命令行运行

可以基于之前生成的镜像来启动容器,当然一个镜像可以启动多个容器,但是一个容器一定是基于某个镜像的。命令比较简单,这里就着重给大家介绍几个常用的配置。

1. 分离模式

以分离模式(detached mode)运行容器,即容器在后台运行,不会将容器的输出打印到终端。

docker run -d my_image

2. 映射端口

将主机的 某个 端口映射到容器的 指定 端口,比如 8080-80,这样可以通过访问主机的 8080 端口来访问容器内运行在 80 端口的服务。

docker run -p 8080:80 my_image

3. 容器命名

为容器命名,方便后续对该容器进行管理和识别。不写则会随机生成,可用 docker ps -a 查找。

docker run --name my_container my_image

4. 挂载目录

将主机上的指定目录挂载到容器内的指定目录,实现数据持久化,并且两侧是同步的。

docker run --name my_container -v /host/data:/container/data my_image

5. 设置环境变量

设置环境变量和值,容器内的应用可以读取这个环境变量。

docker run --name my_container -e MY_ENV_VARIABLE=value my_image

6. 限制内存

限制容器使用的内存,防止容器过度占用主机资源。(Windows 下可能不行,得改 WSL2配置)

docker run --name my_container --memory 512m my_image

7. 限制核心

限制容器最多使用主机 CPU 核心数。(Windows 下可能不行,得改 WSL2配置)

docker run --name my_container --cpus 0.5 my_image

8. 连接网络

将容器连接到 Docker 网络,如果该网络不存在,Docker 会自动创建。这样可以方便容器之间的通信和网络隔离。(当然,网络模式有很多种,我的另一篇有详细介绍)

docker run --name my_container --network my_network my_image

9. 退出重启

设置容器的自动重启策略为总是在退出时自动重启。这在容器因某些原因意外退出时很有用,可以确保服务的连续性。

docker run --name my_container --restart always my_image

容器开启后,就可以运行程序了,当然可以打开新的终端,输入命令进入到容器内部:

   docker exec -it [容器名称或 ID] /bin/bash

这里的 -i 表示允许交互,-t 表示分配一个伪终端。这样就可以进入容器并启动一个 bash shell。

想退出用 exit 即可,但是退出后容器默认会在后台运行。

停止容器:

docker stop [容器名称或 ID]

发送一个 SIGTERM 信号给容器,让容器内的主进程有机会进行优雅的关闭。如果容器在一段时间内(默认是 10 秒)没有停止,Docker 会发送一个 SIGKILL 信号强制停止容器。

删除容器:

docker rm [容器名称或 ID]

删除一个已停止的容器。如果容器正在运行,需要先停止容器才能删除。

docker rm -f [容器名称或 ID]

强制删除一个正在运行的容器。使用这个命令时要注意,可能会导致数据丢失或其他问题。


查看容器日志:

docker logs [容器名称或 ID]

查看容器的日志输出。可以使用-f参数来实时跟踪日志输出。

重启容器:

docker restart [容器名称或 ID]

复制文件:

docker cp [源路径] [容器名称或 ID]:[目标路径]

将本地文件或目录复制到容器中。

docker cp [容器名称或 ID]:[源路径] [目标路径]

将容器中的文件或目录复制到本地。

3.2 Docker Compose

Docker Compose 是一个用于定义和运行多容器应用程序的工具,它是开启精简高效的开发和部署体验的关键。可以一次性启动或停止多个相关容器,提高开发和调试效率。

可以在单个易于理解的 YAML 配置文件中轻松管理服务、网络和卷。然后,通过一个命令,就可以从配置文件中创建并启动所有服务。

注意,适用于多容器和复杂管理的情况,容器较少的情况下就没有必要了。

使用之前需要安装,这里不具体介绍,根据官方文档即可。可以用此命令查看:


使用需要创建一个 docker-compose.yml 文件,在文件中定义服务(容器)、网络、卷等。

这里展示一个示例,包含一个 Web 服务器(Nginx)和一个后端应用(假设是一个 Python Flask 应用):

services:
  web:
    image: nginx
    ports:
      - "8080:80"
    volumes:
      -./nginx_config:/etc/nginx/conf.d
    networks:
      - mynetwork

  app:
    build:.
    command: python app.py
    volumes:
      - app_data:/app/data
    networks:
      - mynetwork
    environment:
      - DB_HOST=db
      - DB_PORT=5432
      - DB_NAME=mydb
      - DB_USER=myuser
      - DB_PASSWORD=mypassword

  db:
    image: postgres
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=mypassword
      - POSTGRES_DB=mydb
    networks:
      - mynetwork

volumes:
  app_data:
  db_data:

networks:
  mynetwork:
    driver: bridge

上面配置中,通过 networks 部分定义了一个名为 mynetwork 的网络,类型为 bridge。三个服务(webapp 和 db)都连接到这个自定义网络,使得它们可以通过服务名称相互通信。

定义了两个卷 app_data 和 db_dataweb 服务将本地的 ./nginx_config 目录挂载到容器内的 /etc/nginx/conf.d,用于配置 Nginx。

app 服务将卷 app_data 挂载到容器内的 /app/data,用于数据存储。db 服务将卷 db_data 挂载到容器内的 /var/lib/postgresql/data,用于 PostgreSQL 数据库的数据存储。

四、总结

上面详细介绍了 Docker 的基本操作,涵盖了生成镜像、运行容器以及管理容器等多方面内容。然而,Docker 作为一款功能极为强大的软件,其能力远不止于此。

在容器间的交互方面,Docker 支持容器间的加密通讯,确保数据在不同容器之间传输的安全性和保密性。通过加密机制,敏感信息得以在复杂的容器化环境中安全流转。

同时,Docker 拥有丰富的插件功能。例如,某些插件可以实现更高效的存储管理,优化容器对存储资源的利用;还有些插件能够增强网络配置的灵活性,为容器间的通讯提供更多定制化的选项。此外,插件还可以与其他工具和技术进行集成,进一步提升 Docker 在不同场景下的适用性和实用性。

官方文档内容也比较多,大家按需学习即可。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐