找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4089

积分

0

好友

534

主题
发表于 5 小时前 | 查看: 2| 回复: 0

内容目录

  1. docker 是什么
  2. docker 解决什么问题
    1. 解决虚拟机资源消耗问题。
    2. 快速部署。
    3. 提供一次性的环境。
    4. 提供弹性的云服务。
    5. 组建微服务架构。
  3. docker 安装部署与使用
    1. 安装 docker 引擎
    2. 使用 docker
      1. 理解 docker 的架构
      2. docker 命令
      3. 卷的概念
      4. 自制镜像并发布
      5. docker 网络
      6. docker pipework
      7. docker 网络端口映射
  4. 总结

docker 可能会改变软件行业

1. docker 是什么

大家应该都用过虚拟机,在 Windows 上装个 Linux 虚拟机是很多程序员的常用方案。公司的生产环境也大多采用虚拟机。虚拟机将物理硬件资源虚拟化,按需分配使用,用起来和真实操作系统一模一样。当废弃不用时,直接删除虚拟机文件即可回收资源,管理起来非常方便。

但虚拟机有个明显缺点:它非常“重”,对硬件资源的消耗也大。于是,Linux 发展出了另一种虚拟化技术——Linux 容器(Linux Containers,缩写为 LXC)。它并不模拟一个完整的操作系统,却能提供类似虚拟机的隔离效果。如果说虚拟机是操作系统级别的隔离,那么容器就是进程级别的隔离。想想看,这种更轻量的隔离级别,优势无疑是启动更快、更节省资源。

Docker,就是对 Linux 容器的一种封装,它提供了简单易用的用户接口,是目前最流行的 Linux 容器解决方案。

下面是百科的定义:

Docker 是基于 Go 语言的开源应用容器引擎,并遵从 Apache 2.0 协议。Docker 让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器完全使用沙箱机制,相互之间不会有任何接口。

2. docker 解决什么问题

1. 解决虚拟机资源消耗问题。

在传统架构下,服务器操作系统之上运行着虚拟机,虚拟机上又运行着客户操作系统,客户操作系统之上才是用户的应用程序。这样一来,一台服务器 80% 的资源开销可能都花在了硬件虚拟化和客户机操作系统本身上。

虚拟机与容器架构对比图

图1. 虚拟机架构与容器架构区别

如图 1 所示,如果采用 Docker 容器技术,情况就大不相同。容器上直接运行着应用,容器和宿主机服务器使用同一内核,容器的文件系统使用物理服务器的文件系统(但做了隔离),看上去每个容器都有自己独立的文件系统。同时,在物理服务器上建立虚拟网桥设备,每个容器通过它连接网络。容器直接使用物理服务器的 CPU、内存、硬盘,无需额外的硬件虚拟化层和完整的客户机操作系统,因此资源消耗极低,单个容器的性能更接近物理服务器的原生性能。

一台普通家用电脑运行一个 Linux 虚拟机可能已经非常卡顿,但却可以使用 Docker 轻松虚拟出几十甚至上百个容器。如果换成性能强劲的服务器,使用 Docker 搭建私有云服务就不再是梦想。

2. 快速部署。

软件开发中的一个经典难题就是环境配置。在自己电脑上运行得好好的软件,换一台机器可能就“趴窝”了,除非你能保证操作系统设置、各种组件和库的安装完全一致。比如部署一个 Java Web 系统,机器必须安装正确版本的 Java、设置好环境变量,可能还得装 Tomcat、Nginx。换个环境,所有步骤都得重来一遍。

使用 Docker,你可以将应用程序及其所有依赖打包成一个文件(Docker 镜像文件)。运行这个镜像,就会启动一个容器,并在容器内运行你的应用,就像在真实的物理机上运行一样。有了 Docker,就能实现“一次构建,处处运行”,这也为自动化发布铺平了道路。

3. 提供一次性的环境。

这对于测试场景非常有用。比如,你想在本地测试别人的软件;或者在持续集成(CI)流程中,需要为单元测试和构建提供干净、一致的环境。用 Docker 启动或关闭一个容器,就像启动或关闭一个进程一样简单快速,秒级完成。

4. 提供弹性的云服务。

正因为 Docker 容器可以做到随开随关,它非常适合需要动态扩容和缩容的场景,这也是现代云服务的核心特性之一。

5. 组建微服务架构。

通过运行多个容器,一台物理机就能轻松模拟出完整的微服务架构,甚至分布式架构。这为开发、测试和演示复杂的系统拓扑提供了极大的便利。

3. docker 安装部署与使用

本文以 Ubuntu 18.04 系统为例进行介绍。其他操作系统请参考 官方文档

1. 安装 docker 引擎

获取最新版本的 Docker 安装包:

aaron@ubuntu:~$ wget -qO- https://get.docker.com/ | sh

执行上述命令,输入当前用户密码,即可自动下载并安装最新版 Docker。

安装完成后会有一个提示:

If you would like to use Docker as a non-root user, you should now consider
adding your user to the "docker" group with something like:

  sudo usermod -aG docker aaron

Remember that you will have to log out and back in for this to take effect!

WARNING: Adding a user to the "docker" group will grant the ability to run
         containers which can be used to obtain root privileges on the
         docker host.
         Refer to https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface
         for more information.

如果你希望以非 root 用户身份直接运行 docker,需要执行:

sudo usermod -aG docker aaron

将用户 aaron 添加到 docker 用户组中,然后重新登录系统,否则可能会遇到如下权限错误:

docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.38/containers/create: dial unix /var/run/docker.sock: connect: permission denied.
See 'docker run --help'.

执行下列命令启动 Docker 引擎:

aaron@ubuntu:~$ sudo service docker start

通常安装成功后已默认设置开机自启。如需手动设置,可执行:

sudo systemctl enable docker
sudo systemctl start docker

最后,运行一个测试容器,验证安装是否成功:

aaron@ubuntu:~$ sudo docker run hello-world

2. 使用 docker

1. 理解 docker 的架构

使用前,先来了解一下 Docker 的基本架构,这有助于你理解后续的命令和概念。

Docker 客户端、主机与注册中心架构图

Docker 架构图

  • Docker 镜像是存放在 Docker 仓库中的文件,它是用于创建 Docker 容器的模板。
  • Docker 容器是独立运行的一个或一组应用,你可以将其理解为前文提到的轻量级虚拟服务器。
  • Docker 主机是一个物理或虚拟的机器,用于执行 Docker 守护进程和容器。
  • Docker 客户端(也就是我们用的命令行工具)通过 Docker API 与 Docker 守护进程进行通信。

2. docker 命令

查看帮助

docker --help  #查看所有命令帮助
docker COMMAND --help #查看具体命令COMMAND的帮助

查看 Docker 系统信息

docker info

可以看到镜像存储池、已用数据大小、总数据大小、基本容器大小、当前运行容器数量等信息。

搜索镜像

你可以从 Docker Hub 等公共仓库搜索他人制作好的镜像。

docker search ubuntu
docker search centos

终端中执行 docker search ubuntu 的结果

搜索 ubuntu 镜像结果

从搜索结果可以看到,有的镜像已经集成了 PHP、Java、Ansible 等应用。你也可以制作包含自己应用或服务的镜像,分享给他人。对方拿到镜像后,无需复杂的环境配置,直接使用 Docker 运行即可,是不是非常方便?

拉取镜像

从仓库下载镜像到本地。

docker pull centos
docker pull ubuntu

导入本地镜像文件

docker load < image_xxx.tar

查看本地镜像列表

docker images
docker images -a

查看镜像详细信息

docker inspect ubuntu

删除镜像

通过镜像名或 ID 来删除。

docker rmi ubuntu

删除全部镜像:

docker rmi $(docker images -q)

查看镜像构建历史

docker history ubuntu

运行容器

你可以把 Docker 容器理解为一个沙盒中运行的进程,这个沙盒包含了进程运行所需的文件系统、系统库、环境变量等资源。但沙盒本身不会自动运行程序,需要你指定一个启动命令。

运行一个 Ubuntu 容器并进入其交互式 Shell:

aaron@ubuntu:~$ docker run -i --name="ubuntu1" --hostname="ubuntu1" ubuntu /bin/sh
cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.2    ubuntu1
whoami
root
uname -a
Linux ubuntu1 4.15.0-34-generic #37-Ubuntu SMP Mon Aug 27 15:21:48 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

上述命令创建了一个名为 ubuntu1、主机名也为 ubuntu1 的容器,并进入了 /bin/sh。在容器内,我们查看了 hosts 文件、当前用户和内核版本(与宿主机一致)。就像在一个全新的操作系统中一样,可以使用各种 Linux 命令。

在另一个终端,用同样的方法创建一个 ubuntu2 容器,然后使用 docker ps 查看正在运行的容器。

终端中执行 docker ps 查看运行中的容器

查看正在运行的容器

输入 exit 即可退出当前容器的交互模式。

后台运行容器

docker run -d ubuntu

命令会返回一串长长的容器 ID。请注意,如果容器内没有持续运行的进程,容器会很快自动退出。

运行容器并指定 MAC 地址

docker run -d --name='centos3' --hostname='centos3' --mac-address="02:42:AC:11:00:24" docker-centos6.10-hadoop-spark

列出所有容器

docker ps -a

列出最近一次启动的容器

docker ps -l

检查容器详细信息

docker inspect centos1

获取容器的各种 ID 和网络信息

# 获取容器完整ID
docker inspect -f '{{.Id}}' centos1

# 获取容器在宿主机上的进程ID(PID)
docker inspect -f '{{.State.Pid}}' centos1

# 获取容器IP地址
docker inspect -f '{{.NetworkSettings.IPAddress}}' centos1

# 获取容器网关
docker inspect -f '{{.NetworkSettings.Gateway}}' centos1

# 获取容器MAC地址
docker inspect -f '{{.NetworkSettings.MacAddress}}' centos1

进入正在运行的容器

除了创建时通过 -i 参数进入,对于已运行的容器,可以使用 exec 命令进入:

docker exec -it centos /bin/sh

查看容器日志

docker logs centos1

查看容器内文件系统的变更

列表会显示 A(增加)、D(删除)、C(改变)三种事件。

docker diff centos1

查看容器内运行的进程

docker top centos1

从容器内复制文件到宿主机

docker cp centos1:/etc/passwd /tmp/
ls /tmp/passwd

通过网络(如SCP)也可以实现同样功能,有时更方便。

停止容器

docker stop centos1

停止所有容器:

docker kill $(docker ps -a -q)

启动已停止的容器

docker start centos1

删除容器

删除前需要先停止容器。

docker stop centos1
docker rm centos1

删除所有容器:

docker kill $(docker ps -a -q)
docker rm $(docker ps -a -q)

3. 卷的概念

为了能够持久化数据以及在容器间共享数据,Docker 引入了卷(Volume)的概念。卷是容器中的一个特殊目录,这个目录下的文件实际存储在宿主机上,而不是容器的可写层中。

数据卷提供了很多有用的特性:

  1. 可以在容器之间共享和重用。
  2. 对数据卷的修改会立即生效。
  3. 对数据卷的更新,不会影响镜像本身。
  4. 数据卷会一直存在,即使容器被删除。

注意:数据卷的使用类似于 Linux 下的 mount 挂载。容器中被指定为挂载点的目录,其原有内容会被隐藏,显示的是挂载的数据卷内容。

创建和使用数据卷

mkdir -p /root/volume1
mkdir -p /root/volume2
docker run -d -v /volume1 --name='centos5' docker-centos6.10-hadoop-spark
docker run -d -v /root/volume1:/volume1 --name='centos6' docker-centos6.10-hadoop-spark
docker run -d -v /root/volume1:/volume1 -v /root/volume2:/volume2 --name='centos7' docker-centos6.10-hadoop-spark
docker run -d -v /root/volume1:/volume1:ro --name='centos8' docker-centos6.10-hadoop-spark

使用 docker run 创建容器时,通过 -v 标记来创建并挂载数据卷。你可以挂载多个卷,可以设置只读属性(ro)。如果不指定宿主机目录(如第一个命令),Docker 会自动在宿主机上创建一个目录,可以通过 docker inspect 查看其具体路径。

可以分别进入这些容器,查看 /volume1/volume2 目录。

数据卷共享

如果想让一个容器访问另一个容器的数据卷,可以使用 --volumes-from 参数。

数据卷容器

这是一种专门用于提供数据卷给其他容器挂载的容器,适合需要在多个容器间共享持续更新数据的场景。

  1. 创建一个名为 dbdata 的数据卷容器:

    docker run -d -v /dbdata --name dbdata docker-centos6.10-hadoop-spark
  2. 在其他容器中使用 --volumes-from 来挂载 dbdata 容器中的数据卷:

    docker run -d --volumes-from dbdata --name db1 docker-centos6.10-hadoop-spark
    docker run -d --volumes-from dbdata --name db2 docker-centos6.10-hadoop-spark

这样,db1db2 容器就能共享 dbdata 容器中 /dbdata 目录的数据了。

4. 自制镜像并发布

提交容器修改以创建新镜像

docker commit centos1 centos111

将现有的容器 centos1 的当前状态提交,形成一个新的镜像 centos111。使用 docker images 可以看到这个新镜像。这是快速创建自定义镜像的一种方法。

查看镜像:

docker images

REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
centos111    latest    d691a75ee371   23 minutes ago  501.5 MB

使用新镜像创建容器:

docker run -d --name='centos111' centos111

导出和导入镜像

当需要将一台机器上的镜像迁移到另一台机器时,就需要用到导出和导入。

在机器A上导出镜像:

docker save docker-centos6.10-hadoop-spark > docker-centos6.10-hadoop-spark2.tar

docker save -o docker-centos6.10-hadoop-spark docker-centos6.10-hadoop-spark2.tar

使用 scp 或其他方式将 docker-centos6.10-hadoop-spark2.tar 文件拷贝到机器B。

在机器B上导入镜像:

docker load < docker-centos6.10-hadoop-spark2.tar

docker load -i docker-centos6.10-hadoop-spark2.tar

发布镜像到仓库

docker push centos6.8-lamp1

这将镜像推送到你配置的镜像仓库(默认为 Docker Hub)。

4. docker 网络

Docker 启动时会在宿主机上创建一个名为 docker0 的虚拟网桥。它会从 RFC 1918 定义的私有地址段中随机选择一个宿主机未使用的地址和子网,默认通常是 172.17.0.1/16。这个 16 位的子网掩码为容器提供了 65534 个可用的 IP 地址。

docker0 不是一个普通的网络接口,而是一个虚拟的以太网桥,可以自动在绑定到它上面的其他网卡间转发数据包,从而实现容器与宿主机、容器与容器之间的通信。

Docker 每创建一个容器,就会创建一对“Veth Pair”接口(可以想象成一根网线的两端)。其中一端作为 eth0 接口放在容器内,另一端以类似 vethAQI2QT 的名称连接到宿主机,并绑定到 docker0 网桥上。这样,所有容器和宿主机就处在同一个虚拟子网中。

Docker NAT 网络

这是 Docker 容器的默认网络模式。容器通过 NAT(网络地址转换)方式访问外网。在这种模式下,容器内可以访问宿主机以外的网络,但宿主机以外的机器无法直接访问容器内部。

Docker Bridge 网络

Bridge 模式也可以让容器访问外网。但与默认模式不同的是,通过额外的配置(如端口映射或自定义网桥),宿主机以外的机器也有可能访问到容器网络。

6. docker pipework

Docker 自带的网络功能相对基础,无法满足一些复杂的应用场景。因此社区涌现了许多增强 Docker 网络能力的开源工具,如 pipework、weave、flannel 等。

pipework 由 Docker 工程师 Jérôme Petazzoni 开发,是一个用 200 多行 Shell 脚本实现的 Docker 网络配置工具,简单易用。

安装 pipework

git clone https://github.com/jpetazzo/pipework
cp pipework/pipework /bin/

wget http://172.17.1.240/docker/software/pipework
chmod a+x pipework
cp pipework /bin/

使用 pipework 配置容器网络

  1. 运行一个不配置网络的容器:

    docker run -d --net='none' --name='centos9' docker-centos6.10-hadoop-spark
  2. 使用 pipework 为容器配置网络,并将其连接到 docker0 网桥。网关地址在 IP 后通过 @ 指定:

    pipework docker0 centos9 172.18.0.100/16@172.18.0.1

7. docker 网络端口映射

对于使用默认 docker0 网络的容器(NAT模式),外网无法直接访问。此时,可以通过端口映射的方式,将容器内的服务端口暴露给宿主机,从而让外部访问。

运行一个容器,并将其 22 端口映射到宿主机的 38022 端口:

docker run -d -p 38022:22 --name='centos10' docker-centos6.10-hadoop-spark

现在,可以通过访问宿主机的 38022 端口来连接容器内的 SSH 服务:

ssh localhost -p 38022

其他服务器也可以通过访问这台物理宿主机的 IP 地址和 38022 端口来访问该容器。

可以一次映射多个端口:

docker run -d -p 38022:22 -p 38080:80 --name='centos11' docker-centos6.10-hadoop-spark

其底层原理是通过宿主机上的 iptables 规则实现端口转发。当然,也可以通过配置 iptables 规则实现整个容器 IP 的转发。

4. 总结

容器作为进程级别的虚拟化技术,相比传统的虚拟机拥有显著优势。

(1)启动快
容器内的应用直接就是宿主机系统的一个进程,而不是虚拟机内部的操作系统进程。所以启动容器相当于启动本机的一个进程,而不是启动一整个操作系统,速度自然快得多。

(2)资源占用少
容器只占用它实际需要的资源,不会像完整的虚拟机操作系统那样占用所有预设资源。多个容器可以共享宿主机内核等资源,而虚拟机通常是资源独享。

(3)体积小
容器镜像只需要包含应用及其运行依赖的组件,而虚拟机镜像则是整个操作系统的打包。因此容器镜像文件通常比虚拟机镜像文件小很多。

总而言之,容器就像一种轻量级的虚拟机,能够提供必要的环境隔离和虚拟化能力,但开销和复杂度却低得多,是现代 DevOps云原生 应用架构中的重要基石。如果你想深入探讨容器技术的更多细节或实践案例,欢迎访问云栈社区与广大开发者交流。




上一篇:Docker容器运行时端口暴露:不重启容器新增映射的3种方法
下一篇:Python数据可视化:6个Matplotlib风格库提升图表颜值与专业度
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-9 08:27 , Processed in 0.804073 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表