愚有一台Ubuntu的服务器,常无事好(hào)折腾,安装部署如有它法,则避之。然近不得已用docker,CSDN其文章误人子弟!反复安装数次,遂请大佬阅之,大佬以为有过,故特意总结整理

以下文章取自Docker 从入门到实践(强烈推荐小白阅读),以及自己的一些理解

旧活新整?小张也开始水文了?!简单食用论在八月初发过一次,当时初次体验docker,现在有了更多的认识(『Docker Compose』越用越香啊!)以及常用命令所以重构一篇

一、安装Docker

安装 Docker 教程中有主流的Ubuntu、Centos、MacOS等安装教程,这里以我的Ubuntu为例

卸载旧版本

旧版本的 Docker 称为 docker 或者 docker-engine,首先卸载旧版本

$ sudo apt-get remove docker \
docker-engine \
docker.io

使用 APT 安装

由于 apt 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书

$ sudo apt-get update		# 先更新一下
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release

为了确认所下载软件包的合法性,需要添加软件源的 GPG 密钥,二选一

# 阿里源
$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 官方源
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

然后,我们需要向 sources.list 中添加 Docker 软件源,二选一

# 阿里源
$ echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 官方源
$ echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

以上命令会添加稳定版本的 Docker APT 镜像源,如果需要测试版本的 Docker 请将 stable 改为 test

安装 Docker

更新 apt 软件包缓存,并安装 docker-ce

$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

启动 Docker

$ sudo systemctl enable docker
$ sudo systemctl start docker

建立 docker 用户组

默认情况下,docker 命令会使用 Unix socket 与 Docker 引擎通讯。而只有 root 用户和 docker 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。

建立 docker 组:

$ sudo groupadd docker

将当前用户加入 docker 组:

$ sudo usermod -aG docker $USER

退出当前终端并重新登录,进行如下测试。

测试 Docker 是否安装正确

$ docker run --rm hello-world
# -----------输出-----------
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:308866a43596e83578c7dfa15e27a73011bdd402185a84c5cd7f32a88b501a24
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

若能正常输出以上信息,则说明安装成功

镜像加速

如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker 国内镜像加速

首先执行以下命令,查看是否在 docker.service 文件中配置过镜像地址。

$ systemctl cat docker | grep '\-\-registry\-mirror'

如果该命令有输出,那么请执行 $ systemctl cat docker 查看 ExecStart= 出现的位置,修改对应的文件内容去掉 --registry-mirror 参数及其值,并按接下来的步骤进行配置。

如果以上命令没有任何输出,那么就可以在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件):

{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}

之后重新启动服务

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

二、什么是Docker

抛开一切官方术语,以我自己的认识,简单理解一下Docker(我一直不想用Docker就是因为错误的安装教程以及晦涩的概念),官方描述看我推荐的文档

Docker 包括三个基本概念

  • 镜像Image
  • 容器Container
  • 仓库Repository

举两个例子去解释

手机里从华为应用商城下载了QQ APP,登录了账号A、账号B。这里下载的软件”QQ”就是一个镜像,聊天所产生的缓存文件就是容器且账号A、B是分开存储的,仓库即华为应用商城

无论c、cpp、java、py都有面向对象,建立一个类,然后实例化两个对象。这里类就是一个镜像,两个实例化对象就是容器,俩个实例调用类中函数及数据互不影响。将类打包并发布到npm、pypi等等或下载别人的模块、包即仓库

以上是我自己的理解,源自自己的一次实践,因为第一次使用很晦涩,我明明卸载干净了但是重装数据还在,是因为容器并没有删除

三、命令

总结一些自己常见的或者可能用到的,方便忘记的时候查阅一些命令

获取镜像

docker pull:从 Docker 镜像仓库获取镜像,格式:

$ docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
  • Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub(docker.io)
  • 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像

例子:

$ docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
92dc2a97ff99: Pull complete
be13a9d27eb8: Pull complete
c8299583700a: Pull complete
Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
Status: Downloaded newer image for ubuntu:18.04
docker.io/library/ubuntu:18.04

上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub (docker.io)获取镜像。而镜像名称是 ubuntu:18.04,因此将会获取官方镜像 library/ubuntu 仓库中标签为 18.04 的镜像。docker pull 命令的输出结果最后一行给出了镜像的完整名称,即: docker.io/library/ubuntu:18.04

从下载过程中可以看到我们之前提及的分层存储的概念,镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 sha256 的摘要,以确保下载一致性。

在使用上面命令的时候,你可能会发现,你所看到的层 ID 以及 sha256 的摘要和这里的不一样。这是因为官方镜像是一直在维护的,有任何新的 bug,或者版本更新,都会进行修复再以原来的标签发布,这样可以确保任何使用这个标签的用户可以获得更安全、更稳定的镜像。

运行镜像

举两个示例,基本包括了常用的所有可选参数

例子1:

$ docker run -it --rm ubuntu:18.04 bash

root@e7009c6ce357:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.1 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

docker run 就是运行容器的命令

  • -it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
  • --rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。
  • ubuntu:18.04:这是指用 ubuntu:18.04 镜像为基础来启动容器。
  • bash:放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是 bash

进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 Ubuntu 18.04.1 LTS 系统。

最后我们通过 exit 退出了这个容器。

例子2:以uptime-kuma这个软件为例子,获取镜像并运行

docker run -d --restart=always -p 3001:3001 -v /xxxx/uptime-kuma/data:/app/data --name uptime-kuma louislam/uptime-kuma:1
  • -d:后台运行
  • --restart=always:重启docker时,自启动容器
  • -p:通过ip+3001端口在web中访问
  • -v/宿主机目录:/容器目录/xxxx/uptime-kuma/data:/app/data表示文件在/xxxx/uptime-kuma/data,如果使用相对路径则在/var/lib/docker/volumes
  • --name:指定容器名字
  • louislam/uptime-kuma:1:获取的镜像名字

转自Docker常用命令 | 心流,其它可选参数:

  • --dns 8.8.8.8: 为容器指定一个dns服务器,默认与宿主一致
  • --dns-search domain:为容器指定一个DNS域名,默认与宿主一致
  • -h "hostname": 指定容器的hostname
  • -e arg="value": 设置环境变量
  • -env-file=[]:从指定文件读入环境变量
  • --cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定的cpu运行
  • -m: 设置容器使用内存最大值
  • --net="bridge": 指定容器的网络连接类型,支持bridge/host/none/container四种类型
  • --link=[]:添加链接到另外一个容器
  • --expose=[]:开放一个端口或一组端口,宿主机使用随机端口映射到开放的端口

列出镜像

docker image lsdocker images:列出已经下载下来的镜像

$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 5f515359c7f8 5 days ago 183 MB
mongo 3.2 fe9198c04d62 5 days ago 342 MB
<none> <none> 00285df0df87 5 days ago 342 MB
ubuntu 18.04 329ed837d508 3 days ago 63.3MB
ubuntu bionic 329ed837d508 3 days ago 63.3MB

列表包含了 仓库名标签镜像 ID创建时间 以及 所占用的空间

镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个 标签。因此,在上面的例子中,我们可以看到 ubuntu:18.04ubuntu:bionic 拥有相同的 ID,因为它们对应的是同一个镜像

列出指定镜像docker image ls [IMAGE ID]docker image ls [REPOSITORY:TAG]

删除镜像

ID可以只输入前三位即短ID,或者根据仓库名、标签删除

$ docker image rm [IMAGE ID]
$ docker image rm [REPOSITORY]
$ docker image rm [REPOSITORY:TAG]

小tips:docker『启动/删除』镜像或者容器,都可以使用短id,只要可以区分唯一id就可以运行,哪怕是前一位或者前两位id

操作容器

查看容器状态(四条指令输出相同):docker container ls -adocker container lsdocker container psdocker ps

终止运行中的容器:docker container stop [CONTAINER ID]

启动已终止的容器: docker container start [CONTAINER ID]

重启运行中的容器:docker container restart [CONTAINER ID]

删除容器(容器未终止添加参数-f ):docker container rm [CONTAINER ID]docker container rm [NAMES]

清除所有已终止的容器:docker container prune

进入容器:docker exec -it [CONTAINER ID] bash

查看/修改环境变量(如果经常需要这样做,推荐使用Docker Compose):

  • vim /var/lib/docker/containers/ID/config.v2.json(json不方便查看)
  • docker inspect <NAME> OR <ID>
  • 进入容器后输入:export
  • 进入容器后输入:vim /proc/1/environ(容器内没有vim编辑器,需要安装很鸡肋!)

查看容器日志:『docker logs [OPTIONS] CONTAINER』

  • 可选参数(翻译自docker logs help):

    • -f--follow:跟随最新输出
    • --since,起始时间
    • -n--tail:指定行数
    • -t--since--until:加入时间戳
  • 查看自启动所有日志:docker logs [CONTAINER ID]

  • 查看最近10行日志:docker logs --tail 10 [CONTAINER ID]docker logs [CONTAINER ID] | -n 10

  • 查看最旧10行日志:docker logs [CONTAINER ID] | head -n 10

  • 关键字日志:docker logs [CONTAINER ID] | grep 关键字,可组合-n

  • 根据时间查看

    • 起始时间:docker logs -f -t --since="2022-11-01" [CONTAINER ID]
    • 近30min:docker logs --since 30m [CONTAINER_ID]
    • 起止时间:docker logs -t --since="2022-11-01T10:23:37" --until "2022-11-01T12:23:37" [CONTAINER_ID]

导出某个容器到本地:docker export [CONTAINER ID],例如:docker export 7691a814370e > ubuntu.tar

容器快照文件导入为镜像:docker import

$ cat ubuntu.tar | docker import - test/ubuntu:v1.0
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB

# 此外,也可以通过指定 URL 或者某个目录来导入,例如
$ docker import http://example.com/exampleimage.tgz example/imagerepo

注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。

Docker Compose

Docker官方的另一个开源项目:『Docker Compose』,优点:

  • 相对于Docker,用户可以自定义一个多容器协同工作的容器,例如Web 服务+后端的数据库服务容器,甚至还包括负载均衡容器等
  • Docker容器命令仍适用Docker Compose,而docker compose可以在docker-compose.yml路径下直接输入命令,而不需要再查看容器ID或容器名称后再输入,例如docker logs uptime-kumadocker compose logs,使用更便捷!
  • 二次修改容器中内容时(环境变量、镜像)只需要对docker-compose.yml重新编辑后重启即可(越用越香,换Compose的主要原因)

注:因为是简单食用,docker-compose.yml文件模板没有过多阐述变量属性,通常拉取镜像时作者都会附一份文件模板说明需要配置的变量,个人认为看懂会用即可。因为与docker命令用法一致,命令改为了docker compose所以命令部分省略了很多

简单食用

先做一个简单的例子,以上面的docker为例

docker run -d --restart=always -p 3001:3001 -v /xxxx/uptime-kuma/data:/app/data --name uptime-kuma louislam/uptime-kuma:1

Docker Compose,在路径下新建docker-compose.yml并写入

version: "3.6"

services:
# 任意命名
uptime-kuma:
# 镜像
image: louislam/uptime-kuma:1
# 容器名称
container_name: uptime-kuma
# 自动重启
restart: always
# 挂载目录
volumes:
- /xxxx/uptime-kuma/data:/app/data
# 打开的端口
ports:
- 3001:3001

启动:docker compose up -d

第二个例子

depends_on指定先启动 redis db 再启动 web

version: '3'

services:
web:
build: .
depends_on:
- db
- redis

redis:
image: redis

db:
image: postgres

第三个例子

使用 context 指令指定 Dockerfile 所在文件夹的路径。使用 dockerfile 指令指定 Dockerfile 文件名。使用 arg 指令指定构建镜像时的变量。

version: '3'
services:

webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
# 设置共享内存2g(shared memory)
shm_size: 2gb
# 环境变量
environment:
- xxx=xxx
- xxx=xxx
args:
buildno: 1

常用命令

验证docker-compose.yml文件是否正确:docker compose config

启动容器:docker compose up -d,其中-d指后台运行容器,不直接输出到bash窗口

查看日志:docker compose logs

停止容器:docker compose stop

启动已停止的容器:docker compose start

重启运行中的容器:docker compose restart

列出Compose中所有容器:docker compose ps

列出Compose中所有镜像:docker compose images

删除所有(停止状态的)服务容器: docker compose rm [options] [SERVICE...],选项:

  • -f, --force 强制直接删除,包括非停止状态的容器。一般尽量不要使用该选项
  • -v 删除容器所挂载的数据卷