简介

Docker是一个开源的容器引擎,它轻巧,且易移植,“build once, configure once and run anywhere”。使用go语言开发,并遵从apache2.0协议。[1]

  • docker要解决的问题

    • 解决当前传统行业中存在的问题
      • 开发、生产、测试环境不一致,开发环境下可用的服务挪到生产上不可用。
      • 不同环境之间迁移成本太高,没有统一的软件部署封装标准及封装环境。
      • 对于分布式软件持续集成(测试、打包、发布、部署、管理)周期很长,难以自动化、工程化。
      • 面临瞬时用户流量增大的场景,很难实现分布式应用服务实例的快速部署。
    • 虚拟机的在某些场景下的性能损耗问题
      • docker是一种虚拟化容器技术,他和虚拟机最根本的区别是:docker容器和宿主机共用linux操作系统内核,不会在宿主机上再次安装操作系统。docker容器运行状态下的本质是宿主机上的进程,通过namespace资源隔离,cgroups资源限制,使它看上去像是一个独立的虚拟机.
      • docker容器与虚拟机的对比:
        对比项 虚拟机 docker容器
        启动速度 龟速(本质是启动操系统) 秒速(本质是启动一个进程)
        镜像大小 以Ubuntu为例,1G以上 Ubuntu: 195M
        应用部署集成 通常都是手动安装 下载镜像+启动镜像(自动)
        内存访问效率 慢,先访问虚拟地址 基本等同于宿主机
        CPU损耗 虚拟机操作系统造成的损耗较大 接近于0
  • docker的应用场景

    • docker镜像一旦构建,就已经一次性完成了应用自动打包、集成。docker镜像可以进行版本管理、复制、分享、修改,就像管理代码一样。(即一次部署处处运行)
    • 通过统一的docker环境封装(比如镜像中封装了同一版本的JDK、同样的环境变量等等),保证应用服务运行环境的一致性。避免出现在测试环境上好用,挪到生产环境下运行失败的问题。
    • docker可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。
    • 因为镜像可下载、可复用,docker容器可快速启动等特性,结合容器编排服务(k8s)可以实现大型分布式部署的弹性伸缩,快速扩展。
  • docker相关网站

  • 安装自行查阅所需系统的相关文档,按文档中的指定步骤安装即可。

Docker黑话

Docker本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成实例(container容器)。一个image镜像可以生成多个同时运行的container容器

  • docker的基本组成
    • 镜像(image) -> 相当于编程中定义的类
    • 容器(container) -> 相当与编程中new出来的类实例
    • 仓库(repository) -> 存放定义类的整个代码文件

第一个命令

docker run hello-world

测试docker环境是否能够正常使用,初步安装后可用该命令测试。

启动相关命令

1
2
3
4
5
6
7
8
systemctl start docker     # 启动
systemctl stop docker # 停止
systemctl restart docker # 重启
systemctl status docker # 查看docker状态
systemctl enable docker # 开机启动
docker info # 查看docker信息
docker --help # 查看帮助文档
docker functive --help # 查看具体功能项的帮助文档,如`docker start --help`

镜像相关命令

1
2
3
4
5
docker images                     # 查看本地镜像列表
docker search *imageName* # 搜索镜像 (从云资源仓库)
docker pull *imageName* # 下载镜像
docker rmi *imageName* # 删除镜像
docker system df # 查看镜像 / 容器 / 数据卷所占的空间

查看本地镜像列表

docker images

1
docker images 

OPTIONS说明:

-a: 列出本地说有的镜像(含历史)
-q: 只显示镜像ID(唯一)

  • 演示

    列头 含义
    REPOSITOTY 表示该镜像的仓库源
    TAG 表示镜像的版本号 -> 比如 redis 3.0 或者像 latest 这样表示最新版本
    IMAGE ID 镜像ID(唯一)
    CREATED 该镜像的创建时间
    SIZE 镜像大小

搜索镜像(从云资源仓库)

1
docker search *imageName* 

OPTIONS说明:

–limit:只列出N个镜像, 默认25个

docker search –limit 5 mysql

  • 演示:

    列头 含义
    NAME 镜像名称
    DESCRIPTION 镜像说明
    STARS 点赞数
    OFFICIAL 是否官方认证
    AUTOMATED 是否是自动构建的

下载镜像

docker pull

1
docker pull *imageName* 

可指定镜像的版本号来下载具体版本

docker pull redis:6.0.8

删除镜像

docker rmi

1
docker rmi *imageName*   

可以删除单个或多个,或是像这样删除所有

docker rmi -f $(docker images -qa)

查看镜像/容器/数据卷所占的空间

docker system df

1
docker system df 
  • 演示

虚悬镜像

docker的虚悬镜像是名称和标签都为

容器相关命令

新建+启动容器

docker run imageName

1
docker run [OPTIONS] *imageName* [COMMAND] [ARG...]

OPTIONS说明

  • –name=”容器新名字” 为容器指定一个名称;
  • -d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
  • -i:以交互模式运行容器,通常与 -t 同时使用;
  • -t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
    即启动交互式容器(前台有伪终端,等待交互);
  • -P: 随机端口映射,大写P
  • -p: 指定端口映射,小写p
    参数 说明
    -p hostPort:containerPort 端口映射 -p 8080:80
    -P ip:hostPort:containerPort 配置监听地址 -p 10.0.0.13:8080:80
    -p ip::containerPort 随机分配端口 -p 10.0.0.13::80
    -p hostPort:containerPort:udp 指定协议 -p 8080:80:tcp
    -p 81:80 -p 443:443 指定多个端口映射
  • 演示

    如图, 使用时通常使用参数-it启动交互式容器,并给其分配交互用的shell,图中用的是/bin/bash

    如果”未使用--name“来给容器指定名字, 则系统会给此容器”随机一个名字”。

列出当前所有正在运行的容器

docker ps [OPTIONS]

OPTIONS说明(常用):

  • -a :列出当前所有正在运行的容器+历史上运行过的
  • -l :显示最近创建的容器。
  • -n:显示最近n个创建的容器。
  • -q :静默模式,只显示容器编号。

退出容器

两种退出方式”exit”退出并停止容器 或 “ctrl+p+q”后台运行

说明:

  • run进去容器后,exit退出,容器停止
  • run进去容器后,ctrl+p+q退出,容器不停止

启动已停止运行的容器

“docker start” 容器ID或者容器名

重启容器

“docker restart” 容器ID或者容器名

停止容器

“docker stop” 容器ID或者容器名

强制停止容器

“docker kill” 容器ID或容器名

删除已停止的容器

“docker rm” 容器ID

正在使用中无法删除删除的容器,可以通过加一个 -f 参数来强制删除

还可一次性删除多个容器实例

如全部删除(不建议的操作,仅供演示哈)

  • docker rm -f $(docker ps -a -q)
  • docker ps -a -q | xargs docker rm xargs 为linux中组合多个命令的常用工具,一般和管道|一起使用(主要是因为很多命令不支持管道来传递参数,所有就有了xargs这个过滤器来组合命令)

(重要)启动守护式容器(后台服务器)

docker run -d 容器名

不过有些容器是无法以守护模式运行的,可能刚一运行起来就自动退出了(docker ps 可查看已经停止运行的容器),所以这部分容器必须以前台进程的形式运行。(不过能使用守护式运行,就尽量使用守护式运行。因为我们后续还可以通过其他命令来单独打开一个与其交互的命令行进程)

来做个前后台启动的演示 以 redis 镜像为例:

  • 前台交互式启动: docker run -it redis:6.0.8
  • 后台守护式启动: docker run -d redis:6.0.8

(重要)查看容器日志

docker logs 容器ID

(重要)查看容器内运行的进程

docker top 容器ID

(重要)查看容器内部细节

docker inspect 容器ID/容器名称

比如有些时候, 我们通过docker compos启动的一系列服务中, 有一个web容器, 而又懒得查看compose.yaml中关于端口映射的配置, 就可以简单的通过这个命令来查看在实体本机上实际使用的端口是哪个。

(重要)进入正在运行的容器并以命令行交互

有如下子标题两种方式,这里解释一下区别:

  • exec 是在容器中以启动新的进程的方式,打开新的终端,因此用exit退出,不会导致容器的停止。
  • attach 直接进入容器启动命令的终端,不会启动新的进程终端,因此用exit退出,会导致容器的停止。

    综上,推荐大家使用 docker exec 命令,因为退出容器终端,不会导致容器的停止。

    假设我们已经打开了一个redis容器实例,我们就可以通过本节命令进入redis服务

    • docker exec -it 容器ID /bin/bash
    • docker exec -it 容器ID redis-cli

      一般用-d后台启动的程序,就用exec进入对应的容器实例。

docker exec -it 容器ID/容器名称 Shell终端路径

  • 如常用的/bin/bash, docker exec -it 容器名称 /bin/bash
  • 当然, 有些非常精简的容器可能连bash都没有安装(比如Redis官方的镜像), 可能只有/bin/sh, docker exec -it 容器名称 /bin/sh 或者试试docker exec -it 容器名称 sh

docker attach 容器ID/容器名称 (实际是重新进入)

(重要)从容器内拷贝文件到主机上

docker cp 容器ID:容器内路径 目的主机路径

此命令对于普通用户的日常使用已经是完全够用了

题外话: Docker还提供了功能更强的容器数据卷功能,容器数据卷功能可满足文件目录的持久化备份甚至是数据共享的需求,如果你认为自己的数据已经重要到需要实时备份甚至服务间数据共享的地步时,请前往初级篇阅读容器数据卷功能的相关操作。

(特别重要)导入和导出容器

按如下子标题操作, 我们可以吧容器重新打包成一个镜像, 然后从镜像实例化容器。

案例

  • docker export *容器ID* > *文件名.tar*
  • cat *文件名.tar* | docker import - *镜像用户/镜像名:镜像版本号*

    比如我们可以对官方ununtu 镜像的实例容器 进行自定义需求环境搭建后, 封装为自己的镜像这样就可以降低以后相同环境搭建的工作量了。不过,单降低工作量来说,通过docker commit命令可以更好的完成这个需求,在随后初级篇中会介绍这个命令,本篇主要从使用以及分享者的角度叙述Docker的用户常用操作,到此已经结束,且完全足够日常使用。如过你是一位开发者,有发布自己镜像的需求,请继续阅读随后篇章。

export 导出容器为tar包

import 导入tar包为镜像

(特别重要)修改容器的映射端口

如果我们启动了一个容器,但是忘记了手动映射宿主机与容器的端口(有的容器不指定的话,是无法简单通过docker psdocker port 容器ID 查看其映射的); 或者是遇到需要更改宿主机的端口 以及 要添加更多宿主及和容器的映射端口地情况。 这些场景下,我们都需要去修改容器地映射端口。

本节介绍一些解决方案供参考使用

新建容器

  1. 如果此时容器还没有开始正式使用,或者是投入使用前无需手动配置太多。(总之比较接近原镜像)

    • 这种情况,不妨直接删除当前容器,然后重新run一个。(记得加上需要地端口映射)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      docker run -id --name="容器名" \
      -p 映射关系1 \
      -p 映射关系2 \
      -p 映射关系3 \
      ...
      -p 映射关系n \
      镜像名 \
      ...
      /bin/bash
  2. 如果容器已经投入使用以及其他类似情况(跟其镜像相比较新增了不少东西)

    • 这种情况,我们可以先停止当前容器后,使用docker commit 命令 初级篇查看此命令用法 基于需要修改地容器构建新镜像,然后删除当前容器,在基于新镜像重新run。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      docker run -id --name="容器名" \
      -p 映射关系1 \
      -p 映射关系2 \
      -p 映射关系3 \
      ...
      -p 映射关系n \
      刚才构建地镜像的名称 \
      ...
      /bin/bash

修改容器配置文件

修改之前,需要停止docker服务(如果你的docker上有多个容器在运行,不建议使用此方法)

命令systemctl stop docker -> 停止docker服务

找到容器存放路径

命令cd /var/lib/docker/containers/ -> 打开容器存放目录

打开要修改的容器对应目录中端口映射相关的配置文件hostconfig.json

命令vim 容器id/hostconfig.json -> 修改/新增 端口映射相关参数

> 注意: "端口号/tcp" 对应容器的端口, "HostPort":"端口号" 对应的是宿主机的端口

打卡要修改容器对应目录中用来暴露容器端口相关的配置文件config.v2.json

命令vim 容器id/config.v2.json -> 暴露容器参与映射的端口

注意: 如果此容器之前无任何端口映射,可能没有对应key:value,因此需自己添加"ExposedPorts":{}这项配置(位置合适即可,也可参考图中位置放在"Try":true这个 key:value 的前面)

最后,需要重启docker服务, 然后重启对应容器服务

命令systemctl restart docker -> 重启docker服务
命令docker restart 对应的容器ID或者容器名 -> 重启停止运行的对应容器

总结及其他常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
attach    Attach to a running container                 # 当前 shell 下 attach 连接指定运行镜像
build Build an image from a Dockerfile # 通过 Dockerfile 定制镜像
commit Create a new image from a container changes # 提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中
create Create a new container # 创建一个新的容器,同 run,但不启动容器
diff Inspect changes on a container’s filesystem # 查看 docker 容器变化
events Get real time events from the server # 从 docker 服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export Stream the contents of a container as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应 import ]
history Show the history of an image # 展示一个镜像形成历史
images List images # 列出系统当前镜像
import Create a new filesystem image from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill Kill a running container # kill 指定 docker 容器
load Load an image from a tar archive # 从一个 tar 包中加载一个镜像[对应 save]
login Register or Login to the docker registry server # 注册或者登陆一个 docker 源服务器
logout Log out from a Docker registry server # 从当前 Docker registry 退出
logs Fetch the logs of a container # 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部源端口
pause Pause all processes within a container # 暂停容器
ps List containers # 列出容器列表
pull Pull an image or a repository from the docker registry server # 从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至docker源服务器
restart Restart a running container # 重启运行的容器
rm Remove one or more containers # 移除一个或者多个容器
rmi Remove one or more images # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
run Run a command in a new container # 创建一个新的容器并运行一个命令
save Save an image to a tar archive # 保存一个镜像为一个 tar 包[对应 load]
search Search for an image on the Docker Hub # 在 docker hub 中搜索镜像
start Start a stopped containers # 启动容器
stop Stop a running containers # 停止容器
tag Tag an image into a repository # 给源中镜像打标签
top Lookup the running processes of a container # 查看容器中运行的进程信息
unpause Unpause a paused container # 取消暂停容器
version Show the docker version information # 查看 docker 版本号
wait Block until a container stops, then print its exit code # 截取容器停止时的退出状态值

参考

[1] docker解决的实际问题及应用场景

[2] Docker与微服务实战笔记-朋友转发文档,未溯源