Docker介绍

Docker是什么?

Docker是一个基于虚拟化技术的平台,利用容器能将操作系统层虚拟化,容器可以表示软件的一个标准化单元,加上自身隔离于宿主机,具有便携性和灵活性[1]

Docker为什么会流行

In conclusion, Docker is popular because it has revolutionized development
Docker, and the containers it makes possible, has revolutionized the software industry and in five short years their popularity as a tool and platform has skyrocketed.

The main reason is that containers create vast economies of scale. Systems that used to require expensive, dedicated hardware resources can now share hardware with other systems. Another is that containers are self-contained and portable. If a container works on one host, it will work just as well on any other, as long as that host provides a compatible runtime.[2]

docker优势:

  • 便携的和自我隔离的;
  • docker的应用使系统(尤其是那些需要昂贵和专用硬件资源的系统)可以分享硬件资源给其他系统。

第一点你可以理解为docker在OS层虚拟化[3]。如果说虚拟机是虚拟化硬件,那么docker是让服务/应用虚拟化。就虚拟机,我的理解是操作系统的运行是依托硬件,因此我说虚拟机是虚拟化硬件。比如你可以把Linux装在VM中,然后打包放在其他机器上运行,只要你拥有VM和VMware Workstation。就docker,以MySQL为例,你可以将使用了很久的MySQL的docker镜像打包,然后到其他机器,只要你拥有Docker应用。因此便携性和隔离性都体现出虚拟化技术的优势。

再讲一点,虚拟化可以保证运行的程式隔离于宿主机。比如XXX同学MySQL装不上,可能是错误的安装步骤,或者参数设置有问题,端口占用等等因素,从OS运行环境看,每台宿主机的环境都是不一样的,而docker可以将docker内的服务与外界隔离,这样就排除了外界环境的干扰。如果每个同学都用docker安装MySQL,安装干扰会少很多。

这点可以延伸了提高了企业交付速度,比如XXX应用经过测试OK,就应用放到docker,然后发给甲方(付款方),或者跑到甲方运行docker然后测试,不管如何从速度上,都是有优势的。

第二点更能带来经济优势。

See also: Top Reasons Why Docker is Popular | by Binal Prajapati | JavaScript in Plain English

名词Docker有两种含义[4]

  • Docker项目,指的是整一个Docker平台,可用于开发者和管理员开发,打包和运行应用。
  • Docker引擎,指的是docker守护进程,用于管理镜像和容器。

Container(容器)[4:1]

容器指的是Docker镜像的一个运行实例。这个术语需要注意两点:实例来自Docker镜像;实例是正在运行的。

Docker如何运作

Docker是C/S架构的。

Docker客户端是用来与Docker Daemon进行沟通的。Docker Daemon又叫Docker Sever。

Docker客户端实际上是docker CLI,用于与Docker Daemon进行沟通。

比如"docker run", "docker push"等命令都是由docker CLI提供。docker开头的命令都是Docker CLI。

用层级关系表示,图解大概是这样:

下图展示了Docker客户端如何与Docker主机进行沟通:

docker pull命令通过Docker CLI发送给Docker daemon,然后Docker daemon从远端拉取镜像到Docker主机。

Refer:Understanding How the Docker Daemon and Docker CLI Work Together — Nick Janetakis

Linux安装Docker

可以使用yum安装或者离线安装[4:2],我使用yum安装。

1
2
3
4
5
6
yum list installed | grep docker	#坚持本地是否安装docker
yum -y install docker #yum安装docker
systemctl start docker #开启docker
systemctl status docker #查看docker状态
docker version #查看docker版本详情
docker images #查看本地docker镜像

Docker中安装MySQL

可以在MySQL docker镜像库查找要拉取的MySQL版本:https://hub.docker.com/_/mysql?tab=tags&page=1&ordering=last_updated。

由于在国内拉取速度太慢了,我们需要选择国内docker镜像源。

我选择的是阿里云进行镜像源加速。实现步骤:

登录阿里云容器镜像服务:https://cr.console.aliyun.com/

创建容器仓库后,获得镜像加速地址。

按照说明文档提示配置/etc/docker/daemon.json后,然后执行

1
2
3
sudo systemctl daemon-reload
sudo systemctl restart docker
docker info

这样就成功了。

我选择安装MySQL 5.7.33 Docker镜像

1
docker pull mysql:5.7.33

查看镜像

1
2
3
[root@localhost /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/mysql 5.7.33 a70d36bc331a 4 weeks ago 449 MB

运行Docker中的MySQL实例

基本的docker run命令格式如下

1
docker run [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]

-i : Keep STDIN open even if not attached。开放标准输入流。

-t : Allocate a pseudo-tty。允许终端通信。

-it : 允许我们通过命令行的方式与容器进行沟通。

-d : Detached。-d=true-d等价,表示让容器允许在独立(隔离)模式。

--name : 标识一个容器,就简单地就是给容器取一个独一无二的名称。因此该选项后面紧跟着名称(identifier)。如果不设置该选项,那么docker run后会自动为这个容器生成一个名称。

-p : Publish a container’s port or a range of ports to the host。主机端口与容器端口绑定。

比如:-p 3312:3306表示主机3312端口与容器3306绑定。

-e : Set any environment variable in the container。为容器设置环境变量。

若要设置多个环境变量,格式为:-e key1=value1 -e key2=value2。

-v : 绑定挂载卷。使用该选项可以让主机指定目录挂载到实例的某个目录,这与mount命令类似。'-v’的使用方法如下

1
-v, --volume=[host-src:]container-dest[:<options>]

比如:-v /opt/docker_v/mysql/conf:/etc/mysql/conf.d等价于–volume=/opt/docker_v/mysql/conf:/etc/mysql/conf.d。意思是将主机指定的文件(/opt/docker_v/mysql/conf)挂载到容器指定的文件(/etc/mysql/conf.d)中

See also: docker run | Docker Documentation

为了让你更好理解这些选项,我们看下面一个例子

1
docker run -itd --name test_mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql

上述命令运行一个mysql实例,“IMAGE"为mysql”,允许命令行通信,容器名称"test_mysql",容器端口3307映射到主机端口3307,设置一个环境变量MYSQL_ROOT_PASSWORD,相等于为MySQL设置管理员密码。

接下来我们运行一个MySQL容器:

首先创建目录

1
2
mkdir -p /storage/docker/mysql-data
mkdir -p /root/docker/test_mysql/conf.d

运行容器

1
2
3
4
5
6
7
8
9
docker run \
-p 3306:3306 \
--name=test_mysql \
--volume=/root/docker/test_mysql/conf.d:/etc/mysql/conf.d \
--volume=/storage/docker/mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d \
--privileged \
mysql:5.7.33

"–privileged"保证MySQL有权限读写挂载文件。

"–volume"将mysql自定义配置和数据库数据持久化到Docker主机,这样删除容器后不会出现数据丢失的情况。

See also: How to Set Up & Configure a MySQL Docker Container {Tutorial}

查看容器信息,默认以JSON格式打印出来:

1
2
[root@localhost ~]# docker inspect test_mysql
......

使用docker ps查看容器运行情况:

1
2
3
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da9b17dbc337 mysql:5.7.33 "docker-entrypoint..." 11 seconds ago Up 9 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp test_mysql

"0.0.0.0:3306->3306/tcp"表示本机的3306端口绑定到容器的3306端口。

利用"docker port [容器] 容器的端口号"查询容器端口是否绑定了主机的端口:

1
2
3
4
[root@localhost ~]# docker port test_mysql
3306/tcp -> 0.0.0.0:3306
[root@localhost ~]# docker port test_mysql 3307
Error: No public port '3307/tcp' published for test_mysql

连接MySQL实例

本地连接MySQL实例

docker exec用于运行命令行来与容器进行通信。

docker exec命令格式如下:

1
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

[OPTIONS] - 请参考docker exec | Docker Documentation

CONTAINER - 容器名称。

COMMAND - 命令。这里应该是宿主机上的可用命令。对于Linux来说,可使用pwd,bash等等。

下面例子展示如何本地连接MySQL实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost /work/blog]# docker exec -it test_mysql bash
root@b4b7c5c8ba56:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.33 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

远程连接MySQL实例(使用Navicat)

我们先查看哪些用户允许远程登录:

1
2
3
4
5
6
7
8
9
10
11
12
13
mysql> use mysql;
...
mysql> select user, host from user
-> ;
+---------------+-----------+
| user | host |
+---------------+-----------+
| root | % |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+---------------+-----------+
4 rows in set (0.00 sec)

我们看host一列:'%'表示允许任何主机连接到MySQL;"localhost"表示只允许本地连接到MySQL。

由user表可知,root用户可用于远程登录。不过我还是记录下创建普通用户用于远程登录:

先在本地连接的MySQL的命令行中创建一个远程用户。首先,进入mysql数据库:

1
use mysql;

然后,创建远程用户:

格式为

1
grant all privileges on *.* to 用户名@"%" identified by "密码" with grant option;

我创建的远程用户如下:

1
2
mysql> grant all privileges on *.* to violet@"%" identified by "123456" with grant option;
Query OK, 0 rows affected, 1 warning (0.00 sec)

最后,刷新权限:

1
2
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

再次查看user表

1
2
3
4
5
6
7
8
9
10
11
mysql> select user, host from user;
+---------------+-----------+
| user | host |
+---------------+-----------+
| root | % |
| violet | % |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+---------------+-----------+
5 rows in set (0.00 sec)

接着我们使用Navicat连接MySQL实例:

Docker管理

列出,停止,删除容器/镜像

下面例子展示如何列出,停止删除容器以及列出,删除镜像:

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
[root@localhost /]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8ef927bcfc25 mysql:5.7 "docker-entrypoint..." 3 minutes ago Created test_mysql
[root@localhost /]# docker stop 8ef927bcfc25
8ef927bcfc25
[root@localhost /]# docker rm 8ef927bcfc25
8ef927bcfc25
[root@localhost /]# docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@localhost /]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/mysql 5.7 a70d36bc331a 4 weeks ago 449 MB
[root@localhost /]# docker image rm a70d36bc331a
Untagged: docker.io/mysql:5.7
Untagged: docker.io/mysql@sha256:b3d1eff023f698cd433695c9506171f0d08a8f92a0c8063c1a4d9db9a55808df
Deleted: sha256:a70d36bc331a13d297f882d3d63137d24b804f29fa67158c40ad91d5050c39c5
Deleted: sha256:50c77bf7bcddd1f1d97789d80ac2404eec22c860c104e858620d2a2e321f0ef7
Deleted: sha256:14244329b83dfc8982398ee4104a548385652d2bffb957798ff86a419013efd6
Deleted: sha256:6d990477f90af28473eb601a9bca22253f6381e053c5a8edda0a4f027e124a3c
Deleted: sha256:ee0449796df204071589162fc16f8d65586312a40c68d1ba156c93c56f5e5ce8
Deleted: sha256:d08533f1e2acc40ad561a46fc6a76b54c739e6b24f077c183c5709e0a6885312
Deleted: sha256:4f9d91a4728e833d1062fb65a792f06e22e425f63824f260c8b5a64b776ddc38
Deleted: sha256:20bf4c759d1b0d0e6286d2145453af4e0e1b7ba3d4efa3b8bce46817ad4109de
Deleted: sha256:a9371bbdf16ac95cc72555c6ad42f79b9f03a82d964fe89d52bdc5f335a5f42a
Deleted: sha256:5b02130e449d94f51e8ff6e5f7d24802246198749ed9eb064631e63833cd8f1d
Deleted: sha256:ab74465b38bc1acb16c23091df32c5b7033ed55783386cb57acae8efff9f4b37
Deleted: sha256:cb42413394c4059335228c137fe884ff3ab8946a014014309676c25e3ac86864

如何运行停止的容器

1
docker start `docker ps -q -l`

-l - 显示最新创建的容器

-q - 只显示容器ID

See also: https://stackoverflow.com/questions/21928691/how-to-continue-a-docker-container-which-has-exited。

挂载权限问题解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost ~]# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active (running) since Sat 2021-02-20 20:26:29 CST; 17min ago
Docs: http://docs.docker.com
Main PID: 1834 (dockerd-current)
Tasks: 24
Memory: 10.5M
CGroup: /system.slice/docker.service
├─1834 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdrive...
└─1840 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir ...

Feb 20 20:26:29 localhost.localdomain dockerd-current[1834]: time="2021-02-20T20:26:29.579501459+08:00" level=info msg="Daemon has completed initialization"
Feb 20 20:26:29 localhost.localdomain dockerd-current[1834]: time="2021-02-20T20:26:29.579610063+08:00" level=info msg="Docker daemon" commit="0be3e21/1.13.1" g...n=1.13.1
Feb 20 20:26:29 localhost.localdomain dockerd-current[1834]: time="2021-02-20T20:26:29.583592776+08:00" level=info msg="API listen on /var/run/docker.sock"
Feb 20 20:26:29 localhost.localdomain systemd[1]: Started Docker Application Container Engine.
Feb 20 20:26:36 localhost.localdomain dockerd-current[1834]: 2021-02-20 12:26:36+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.33-1debian10 started.
Feb 20 20:26:36 localhost.localdomain dockerd-current[1834]: 2021-02-20 12:26:36+00:00 [ERROR] [Entrypoint]: mysqld failed while attempting to check config
Feb 20 20:26:36 localhost.localdomain dockerd-current[1834]: command was: mysqld --verbose --help
Feb 20 20:26:36 localhost.localdomain dockerd-current[1834]: mysqld: Can't read dir of '/etc/mysql/conf.d/' (Errcode: 13 - Permission denied)
Feb 20 20:26:36 localhost.localdomain dockerd-current[1834]: mysqld: [ERROR] Fatal error in defaults handling. Program aborted!
Feb 20 20:26:36 localhost.localdomain dockerd-current[1834]: time="2021-02-20T20:26:36.709981942+08:00" level=warning msg="155b85aebe93f507939911baf4ea8e3ee18be...rgument"
Hint: Some lines were ellipsized, use -l to show in full.

Refer: https://github.com/docker-library/mysql/issues/714。

更换挂载目录权限,因为docker mysql需要更高的权限。

删除出问题的容器,然后加入"–privileged"选项:

1
2
3
4
5
6
7
8
9
docker run \
-p 3307:3307 \
--name=test_mysql \
--volume=/root/docker/test_mysql/conf.d:/etc/mysql/conf.d \
--volume=/storage/docker/mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d \
--privileged \
mysql:5.7.33
1
2
3
[root@localhost ~/docker/test_mysql/conf.d]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4b7c5c8ba56 mysql:5.7.33 "docker-entrypoint..." 2 minutes ago Up 2 minutes 3306/tcp, 33060/tcp, 0.0.0.0:3307->3307/tcp test_mysql

第二种解决方法:

修改挂载文件的读写权限。

友情提示:为了避免莫名其妙的错误,请把swap分区和RAM加大。

常用命令Doc

参考 描述
docker ps | Docker Documentation 列出容器信息
docker run | Docker Documentation 运行一个新的容器
docker network | Docker Documentation 管理Docker网络

Docker —— 从入门到实践



  1. Docker - 维基百科,自由的百科全书 ↩︎

  2. What is Docker, and why is it so popular? · Raygun Blog ↩︎

  3. Docker - 维基百科,自由的百科全书 ↩︎

  4. Glossary | Docker Documentation ↩︎ ↩︎ ↩︎