侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 285 篇文章
  • 累计创建 125 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Docker教程-2-MySql容器的安装配置使用

孔子说JAVA
2021-10-15 / 0 评论 / 1 点赞 / 202 阅读 / 12,984 字 / 正在检测是否收录...

1、环境检查

首先检查服务器是否安装了Docker服务,通过docker -v 或 docker info 命令查看docker版本等相关信息,若不识别docker命令表示未安装Docker服务。可参考《Docker教程-1-学习及安装Docker》进行docker的安装配置。

image-1648977412388

2、Docker容器中管理数据的方式

为了很好的实现数据保存和数据共享,Docker提出了Volume这个概念,简单的说就是绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上,又被称作数据卷。Docker容器中管理数据主要有两种方式:

  • 数据卷 : 容器内的数据直接映射到本地主机环境
  • 数据卷容器: 使用特定容器维护数据卷


容器随时可以停止、或者删除。当容器被rm掉,容器里的数据将会丢失。为了避免数据丢失,用户可以使用数据卷挂载来存储数据。

数据卷(volume) 是一个可供一个或多个容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似于Linux中的mount行为。数据卷不属于联合文件系统,因此能够绕过Union File System 提供一些用于持续存储或共享数据的特性;卷的设计目的就是数据持久化,完全独立于容器的生命周期,因此docker不会在容器删除时,删除其挂载的数据卷。特点如下:

  • 数据卷可在容器之间共享或重用数据。
  • 卷中的更改可以直接生效。
  • 数据卷中的更改,不会包含在镜像中的更新。
  • 数据卷的生命周期一直持续到没有容器使用它为止。

数据卷类型:

  • volume:普通数据卷,映射到主机/var/lib/docker/volumes 路径下,一般不需要、也不应该访问这个位置。
  • bind: 绑定数据卷,映射到主机指定路径下
  • tmpfs: 临时数据卷,只存在于内存中

数据卷和挂载目录的区别:

  • 卷 (Docker Volume) 是受控存储,是由 Docker 引擎进行管理维护的。因此使用卷,你可以不必处理 uid、SELinux 等各种权限问题,Docker 引擎在建立卷时会自动添加安全规则,以及根据挂载点调整权限。并且可以统一列表、添加、删除。另外,除了本地卷外,还支持网络卷、分布式卷。
  • 挂载目录,属于用户自行维护。须手动处理所有权限问题。特别是在 CentOS 上,很多人碰到 Permission Denied,就是因为没有使用卷,而是挂载目录,而且还对 SELinux 安全权限一无所知导致。

通过docker run 的 -v 参数或者 docker-compose.yml 的 volumes指定。使用命名卷的好处是可以复用,其它容器可以通过这个命名数据卷的名字来指定挂载,共享其内容(不过要注意并发访问的竞争问题)。比如,Dockerfile 中说 VOLUME /data,那么如果直接 docker run,其 /data 就会被挂载为匿名卷,向 /data 写入的操作不会写入到容器存储层,而是写入到了匿名卷中。但是如果运行时docker run -v mydata:/data,这就覆盖了 /data 的挂载设置,要求将 /data 挂载到名为 mydata 的命名卷中。所以说 Dockerfile 中的 VOLUME 实际上是一层保险,确保镜像运行可以更好的遵循最佳实践,不向容器存储层内进行写入操作。

3、查看可用的 MySQL 版本

访问 MySQL 镜像库地址:https://hub.docker.com/_/mysql?tab=tags 。可以通过 Sort by 查看其他版本的 MySQL,默认是最新版本 mysql:latest 。

image-1648977642818

  • 还可通过docker search mysql 查找Docker Hub或其他Docker仓库中的mysql可用版本镜像。

image-1648977657741

4、下载所需版本的MySQL镜像

1)下载mysql8.0.26版本镜像

# 下载mysql8.0.26版本
docker pull mysql:8.0.26

# 不带版本号默认下载最新版本
docker pull mysql

image-1648977701531

2)查看是否已下载mysql8.0.26版本镜像文件

docker images 查看系统中的镜像文件是否包含刚下载的mysql镜像,可以看到mysql 8.0.26版本已经下载到本地。

# 查看系统中已有的Docker镜像文件
root@xnzysq20210118001:~# docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
mysql         8.0.26    9da615fced53   2 days ago    514MB
nginx         latest    87a94228f133   2 days ago    133MB
nginx         web       87a94228f133   2 days ago    133MB
mongo         latest    c1a14d3979c5   13 days ago   691MB
hello-world   latest    feb5d9fea6a5   3 weeks ago   13.3kB

5、创建 mysql 容器

5.1 --volume/-v和–mount区别

在用 docker run 命令的时候,可以使用--volume/-v 或 --mount选项来创建带有数据卷的容器,但这两个选项有些微妙的差异使用。在一次 docker run 中可以挂载多个数据卷。

1)参数–volume(或简写为-v)只能创建bind mount。

示例:

docker run --name $CONTAINER_NAME -it \
-v $PWD/$CONTAINER_NAME/app:/app:rw \
-v $PWD/$CONTAINER_NAME/data:/data:ro \
avocado-cloud:latest /bin/bash

# 注释:
# 命令格式:[[HOST-DIR:]CONTAINER-DIR[:OPTIONS]]]
# 如果指定HOST-DIR则必须是绝对路径,如果路径不存在则会自动创建
# 实例中的rw为读写,ro为只读

2)–mount,默认情况下用来挂载volume,也可以用来创建bind mount和tmpfs。

如果不指定type选项,则默认为挂载volume,volume是一种更为灵活的数据管理方式,volume可以通过docker volume命令集被管理。示例:

docker run --name $CONTAINER_NAME -it \
--mount type=bind,source=$PWD/$CONTAINER_NAME/app,destination=/app \
--mount source=${CONTAINER_NAME}-data,destination=/data,readonly \
avocado-cloud:latest /bin/bash

# 注释:
# 挂载volume命令格式:[type=volume,]source=my-volume,destination=/path/in/container[,...]
# 创建bind mount命令格式:type=bind,source=/path/on/host,destination=/path/in/container[,...]
# 如果创建bind mount并指定source则必须是绝对路径,且路径必须已经存在
# 示例中readonly表示只读

3)创建bind mount和挂载volume的比较

image-1648977943162

  • 注释:Docker无法简单地通过sudo chown someuser: -R /var/lib/docker/volumes/somevolume来将volume的内容开放给主机上的普通用户访问,如果开放更多权限则有安全风险。而这点上Podman的设计就要理想得多,volume存放在$HOME/.local/share/containers/storage/volumes/路径下,即提供了便捷性,又保障了安全性。无需root权限即可运行容器,这正是Podman的优势之一,实际使用过程中的确受益良多。

4)创建bind mount时使用–volume和–mount的比较

image-1648977970768

5.2 非挂载卷方式创建 mysql 容器

此种方式创建容器,当容器被删除掉时,容器里的数据将会丢失。

1)创建容器

docker run -p 3306:3306 --name mysql8.0.26 -e MYSQL_ROOT_PASSWORD=111111  -e TZ="Asia/Shanghai" -d mysql:8.0.26
  • –name  指定容器的名称为mysql8.0.26
  • -p  将容器内的3306端口与本地3306接口映射,前者是本地访问端口,后者是容器内部端口
  • -e  添加了一个环境变量MYSQL_ROOT_PASSWORD,该变量定义的111111为root密码
  • -e  添加了一个环境变量TZ,指定容器时区,不指定的话mysql的时间函数执行结果会不正确
  • -d  后台运行容器,并返回容器ID
  • 命令最后的mysql:8.0.26   运行指定的镜像创建容器
  • –restart=always 设置随服务启动而启动容器
  • 对于已经运行但没设置随docker服务的启动而启动容器的可以执行命令 docker update –restart=always 容器名

–restart=always参数能够使我们在重启docker时,自动启动相关容器。Docker容器的重启策略如下:

  • no,默认策略,在容器退出时不重启容器
  • on-failure,在容器非正常退出时(退出状态非0),才会重启容器
  • on-failure:3,在容器非正常退出时重启容器,最多重启3次
  • always,在容器退出时总是重启容器
  • unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器

image-1648978166155

上图的错误提示表示绑定的本地3306端口已经被占用(这是因为本地已安装了mysql),通过docker ps -al查看最近创建的容器,可以看到mysql8.0.26容器已经创建完成。

2)关闭本地mysql服务,重启doceker mysql容器

service mysql stop

docker start mysql8.0.26

docker ps 或 docker ps -al
  • 通过service mysql stop 命令关闭本地mysql服务,释放被占用的3306端口。
  • 通过docker start mysql8.0.26 启动mysql容器(这里的mysql8.0.26是容器名称,也可以用容器id指定)。
  • 通过docker ps 或 docker ps -al 命令可以查看到mysql:8.0.26容器已启动成功。

image-1648978205552

3)创建第二个容器

docker run -p 3307:3306 --name mysql8.0.261 -e MYSQL_ROOT_PASSWORD=111111  -e TZ="Asia/Shanghai" -d mysql:8.0.26

与第一个容器不同的地方有2点:

  • 1是映射到本地的访问端口(3307)不同。
  • 2是容器名称不同(mysql8.0.261)。

5.3 挂载本地目录方式创建 mysql 容器

优点:

  • 直接挂载主机,方便管理及备份

缺点:

  • 基于主机,不能在Dockerfile中使用
  • 移植性不好
  • 不方便在多个容器共享

1)创建mysql目录用于存储mysql数据

使用命令:mkdir -p /usr/local/docker/mysql 创建目录。在该目录下接着创建3个目录:conf.d、data、logs。

image-1648978298584

2)在/usr/local/docker/mysql/conf.d 目录下创建配置文件my.cnf及添加如下内容

[mysqld]
user=mysql
character-set-server=utf8
default_authentication_plugin=mysql_native_password
secure_file_priv=/var/lib/mysql
expire_logs_days=7
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
max_connections=1000
 
[client]
default-character-set=utf8
 
[mysql]
default-character-set=utf8

image-1648978334521

3)创建容器

默认挂载的路径权限为读写。如果指定为只读可以用:ro

docker run -p 3306:3306 \
--name mysql8.0.26 \
--privileged=true \
--restart unless-stopped \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-v /usr/local/docker/mysql/conf.d:/etc/mysql/conf.d \
-v /usr/local/docker/mysql/logs:/var/log/mysql \
-v /etc/localtime:/etc/localtime \
-e MYSQL_ROOT_PASSWORD=111111 \
-e TZ="Asia/Shanghai" \
-d mysql:8.0.26
  • –name  指定容器的名称为mysql8.0.26
  • –privileged=true  挂载文件权限设置,使容器内root拥有真正的root权限
  • –restart unless-stopped  设置 开机后自动重启容器
  • -p  将容器内的3306端口与本地3306接口映射,前者是本地访问端口,后者是容器内部端口
  • -v 挂载宿主目录到容器目录,格式为:主机(宿主)目录:容器目录
  • -v /usr/local/docker/mysql/data:/var/lib/mysql \  挂载数据文件 持久化到主机
  • -v /usr/local/docker/mysql/conf.d:/etc/mysql/conf.d \   挂载配置文件
  • -v /usr/local/docker/mysql/logs:/var/log/mysql \    挂载日志
  • -v /etc/localtime:/etc/localtime    容器时间与宿主机同步
  • -e  添加了一个环境变量MYSQL_ROOT_PASSWORD,该变量定义的111111为root密码
  • -e  添加了一个环境变量TZ,指定容器时区,不指定的话mysql的时间函数执行结果会不正确
  • -d  后台运行容器,并返回容器ID
  • 命令最后的mysql:8.0.26   运行指定的镜像创建容器
  • –restart=always 设置随服务启动而启动容器
  • 对于已经运行但没设置随docker服务的启动而启动容器的可以执行命令 docker update –restart=always 容器名
-v /usr/local/docker/mysql/data:/var/lib/mysql

等同于
–mount type=bind,source=/usr/local/docker/mysql/data, target=/var/lib/mysql

image-1648978437660

-v 等同于 --mount type=bind

$ docker run -d -P \
    --name web \
    # -v /src/webapp:/usr/share/nginx/html \
    --mount type=bind,source=/src/webapp,target=/usr/share/nginx/html \
    nginx:alpine

4)创建第二个容器

1.创建第二个容器的配置文件

进入到 /usr/local/docker/ 目录,复制mysql目录,生成mysql2目录。使用命令:cp -r mysql mysql2。此时mysql2目录下的文件和mysql一样。

image-1648978519879

2.创建第二个容器

docker run -p 3307:3306 \
--name mysql8.0.261 \
--privileged=true \
--restart unless-stopped \
-v /usr/local/docker/mysql2/data:/var/lib/mysql \
-v /usr/local/docker/mysql2/conf.d:/etc/mysql/conf.d \
-v /usr/local/docker/mysql2/logs:/var/log/mysql \
-v /etc/localtime:/etc/localtime \
-e MYSQL_ROOT_PASSWORD=111111 \
-e TZ="Asia/Shanghai" \
-d mysql:8.0.26

创建第二个容器的脚本与第一个容器不同的地方有3点:

  • 1是映射到本地的访问端口(3307)不同。
  • 2是容器名称不同(mysql8.0.261)。
  • 3是本地主机(宿主)目录不同(在mysql2下)。

image-1648978557694

5)查看容器详细信息

通过docker inspect 容器名或容器id,查看宿主机的完整挂载路径。

image-1648978576020

image-1648978585985

6)遇到的问题

查看docker的log日志,显示权限不足,大致如下:请确认该目录存在,并且可以被MySQL服务器访问。

[root@mocar mysql]# docker logs 2651
2021-02-05 16:59:16+08:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.20-1debian10 started.
2021-02-05 16:59:16+08:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2021-02-05 16:59:16+08:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.20-1debian10 started.
mysqld: Error on realpath() on '/var/lib/mysql-files' (Error 2 - No such file or directory)
2021-02-05T08:59:17.166792Z 0 [ERROR] [MY-010095] [Server] Failed to access directory for --secure-file-priv. Please make sure that directory exists and is accessible by MySQL Server. Supplied value : /var/lib/mysql-files

解决方案:

linux下:修改my.cnf 在[mysqld]内加入secure_file_priv=/var/lib/mysql

secure_file_priv=/var/lib/mysql

5.4 挂载数据卷方式创建 mysql 容器

优点:

  • 方便在多个容器共享

缺点:

  • 备份相对麻烦些

1)创建一个数据卷并查看数据卷信息

# 创建一个数据卷:
docker volume create my-vol

# 查看所有数据卷
docker volume ls

# 查看指定 数据卷 的信息
docker volume inspect my-vol

# 删除数据卷
docker volume rm 卷名1 卷名2 … 删除一个或者多个数据卷
docker volume prune 删除所有未被使用的数据卷

image-1648978699626

2)数据卷的挂载

我们在创建容器的时候要想好容器的哪些目录需要挂载数据卷!在创建容器时使用 --volume/-v或–mount 选项就可以挂载数据卷了。

方式一:创建自volume名称为my-vol的容器: 若my-vol没有则自动创建

docker run -d --name mysql2 -v my-vol:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
-v {指定的data volume的名称}:{容器内要挂载的路径(同Dockerfile中VOLUME定义的路径)}
查看volume如下
docker volume ls
DRIVER              VOLUME NAME
local               efcfec6f13b6efc66be2f0f73b5895b7b2324937e993e375afd1018443ca5f5b
local               mysql

方式二:使用–mount

docker run --name xxxx -p 8888:8888 --mount   
type:volume,source=/src/xxx,target=/xxx /my:/docker -it imagename /bin/bash
  • type选项,其可以是bind,volume,或 tmpfs。

  • 注意:使用-v参数时如果本地目录不存在Docker会自动为你创建一个文件夹。使用–mount参数时如果本地目录不存在,Docker会报错。Docker挂载主机目录的默认权限是读写,用户也可以通过增加readonly指定为只读。

3)数据卷容器共享

数据卷容器顾名思义也是一个容器,它的目的是专门提供数据卷给其他容器挂载。

创建一个数据卷容器

docker run -it -v /dbdata --name dbdata ubuntu

使用其他容器挂载数据卷容器

docker run -it --volumes-from dbdata --name db1 ubuntu
docker run -it --volumes-from dbdata --name db2 ubuntu
# 匿名挂载数据卷(不建议)

如:docker run -d -P -v /etc/nginx --name nginx01 nginx

# 具名挂载数据卷

如:docker run -d -P -v has-name-nginx:/etc/nginx --name nginx01 nginx

# 查看某个具名挂载卷的详细信息
docker volume inspect has-name-nginx
[
    {
        "Mountpoint": "/var/lib/docker/volumes/has-name-nginx/_data"
    }
]

# 查看容器详细信息
docker inspect 容器ID

# 数据卷读写权限
# ro即readonly,容器对该路径只读,宿主机可读写
-v 容器内路径:ro
# rw即readwrite,容器对该路径可读可写(默认)
-v 容器内路径:rw

容器之间传递共享数据卷
# --volumes-from my_centos01 使用my_centos01的挂载数据卷设置来运行my_centos02容器
# --volumes-from可以重复指定多个
docker run -it --name my_centos01 my_centos:1.0 /bin/bash
docker run -it --name my_centos02 --volumes-from my_centos01 my_centos:1.0 /bin/bash
docker run -it --name my_centos03 --volumes-from my_centos01 my_centos:1.0 /bin/bash

6、mysql容器的开机自启动/停用/重启/删除

1)设置开机自动启动容器

在运行docker容器时可以加如下参数来保证每次docker服务重启后容器也自动重启:

  • docker run --restart=always 容器id或容器名称

如果已经启动了,没有设置开机启动,则可以使用如下命令:

  • docker update --restart=always 容器id或容器名称

2)mysql容器的停用

  • 停用:docker stop 容器id或容器名称

3)mysql容器的启动/重启

  • 启动:docker start 容器id或容器名称
  • 重启:docker restart 容器id或容器名称

4)mysql容器的停用

  • 停用:docker stop 容器id或容器名称

5)mysql容器的删除

  • 停用后删除:docker rm 容器id或容器名称
  • 强制删除(运行中的也可以删除):docker rm -f 容器id或容器名称

image-1648978909740

docker容器删除后,非挂载的方式将会丢失数据。

7、mysql容器配置

7.1 进入mysql容器

# mysql8.0.26 是容器名称,也可以用容器id指定
docker exec -it mysql8.0.26 /bin/bash

image-1648978951675

7.2 更改容器内mysql8.0加密规则

mysql 8.0之后更改了密码的加密规则,把加密方法改回去。否则直接连接数据库报错。

# 登录mysql
mysql -uroot -p111111

# 更改加密规则,依次执行下列3条语句
alter user 'root'@'%' identified by '111111' password expire never;
alter user 'root'@'%' identified with mysql_native_password by '111111';
flush privileges;

# 查看加密规则,修改之前8.0默认的加密方式是 caching_sha2_password
use mysql;  #设置使用的库名为mysql
select user,plugin from user where user='root'; #查询root用户使用的加密插件

image-1648979000329

7.3 mysql容器开启root远程访问

登录mysql后,切换到mysql数据库,修改user表中root用户的host信息,开放root账户所有权限。

  • 注意,在真实的生产环境中,并不建议这么修改,因为安全风险太大。建议根据实际情况将root用户的host项修改为某个指定的ip地址,或仍然保持localhost最后一项设置。
# 切换到mysql数据库
use mysql

# 修改user表中root用户的host信息
update user set host='%' where user='root';

# 开放root账户所有权限
GRANT ALL ON *.* TO 'root'@'%';

# 使各种权限设置立即生效
flush privileges;

image-1648979035106

  • user表中如果已经存在root对应host为%的记录,上述第二条修改root的语句就不需要执行。

8、mysql 验证

在本地使用navicat连接docker mysql 容器,连接成功(和服务器上直接安装mysql的使用方式一样)。

image-1648979055452

使用Navicat创建数据库和数据表。

image-1648979064651

9、Docker是否适合部署数据库

9.1 数据安全问题

  • 容器的 Volumes 设计是围绕 Union FS 镜像层提供持久存储,数据安全缺乏保证。如果容器突然崩溃,数据库未正常关闭,可能会损坏数据。另外,容器里共享数据卷组,对物理机硬件损伤也比较大。

  • 即使你要把 Docker 数据放在主机来存储 ,它依然不能保证不丢数据。Docker volumes 的设计围绕 Union FS 镜像层提供持久存储,但它仍然缺乏保证。

  • 使用当前的存储驱动程序,Docker 仍然存在不可靠的风险。如果容器崩溃并数据库未正确关闭,则可能会损坏数据。

9.2 性能问题

  • MySQL 属于关系型数据库,对IO要求较高。当一台物理机跑多个时,IO就会累加,导致IO瓶颈,大大降低 MySQL 的读写性能。

  • 在一次Docker应用的十大难点专场上,某国有银行的一位架构师也曾提出过:“数据库的性能瓶颈一般出现在IO上面,如果按 Docker 的思路,那么多个docker最终IO请求又会出现在存储上面。现在互联网的数据库多是share nothing的架构,可能这也是不考虑迁移到 Docker 的一个因素吧”。

针对性能问题有些同学可能也有相对应的方案来解决:

(1)数据库程序与数据分离

  • 如果使用Docker 跑 MySQL,数据库程序与数据需要进行分离,将数据存放到共享存储,程序放到容器里。如果容器有异常或 MySQL 服务异常,自动启动一个全新的容器。另外,建议不要把数据存放到宿主机里,宿主机和容器共享卷组,对宿主机损坏的影响比较大。

(2)跑轻量级或分布式数据库

  • Docker 里部署轻量级或分布式数据库,Docker 本身就推荐服务挂掉,自动启动新容器,而不是继续重启容器服务。

(3)合理布局应用

  • 对于IO要求比较高的应用或者服务,将数据库部署在物理机或者KVM中比较合适。目前TX云的TDSQL和阿里的Oceanbase都是直接部署在物理机器,而非Docker 。

9.3 网络问题

  • 要理解 Docker 网络,您必须对网络虚拟化有深入的了解。也必须准备应付好意外情况。你可能需要在没有支持或没有额外工具的情况下,进行 bug 修复。

  • 我们知道:数据库需要专用的和持久的吞吐量,以实现更高的负载。我们还知道容器是虚拟机管理程序和主机虚拟机背后的一个隔离层。然而网络对于数据库复制是至关重要的,其中需要主从数据库间 24/7 的稳定连接。未解决的 Docker 网络问题在1.9版本依然没有得到解决。

  • 把这些问题放在一起,容器化使数据库容器很难管理。我知道你是一个较高级的工程师,什么问题都可以得到解决。但是,你需要花多少时间解决 Docker 网络问题?将数据库放在专用环境不会更好吗?节省时间来专注于真正重要的业务目标。

9.4 状态

  • 在 Docker 中打包无状态服务是很酷的,可以实现编排容器并解决单点故障问题。但是数据库呢?将数据库放在同一个环境中,它将会是有状态的,并使系统故障的范围更大。下次您的应用程序实例或应用程序崩溃,可能会影响数据库。

  • 知识点:在 Docker 中水平伸缩只能用于无状态计算服务,而不是数据库。

  • Docker 快速扩展的一个重要特征就是无状态,具有数据状态的都不适合直接放在 Docker 里面,如果 Docker 中安装数据库,存储服务需要单独提供。

  • 目前,TX云的TDSQL(金融分布式数据库)和阿里云的Oceanbase(分布式数据库系统)都直接运行中在物理机器上,并非使用便于管理的 Docker 上。

9.5 资源隔离

  • 资源隔离方面,Docker 确实不如虚拟机KVM,Docker是利用Cgroup实现资源限制的,只能限制资源消耗的较大值,而不能隔绝其他程序占用自己的资源。如果其他应用过渡占用物理机资源,将会影响容器里 MySQL 的读写效率。

  • 需要的隔离级别越多,获得的资源开销就越多。相比专用环境而言,容易水平伸缩是Docker的一大优势。然而在 Docker 中水平伸缩只能用于无状态计算服务,数据库并不适用。

  • 我们没有看到任何针对数据库的隔离功能,那为什么我们应该把它放在容器中呢?

9.6 云平台的不适用性

  • 大部分人通过共有云开始项目。云简化了虚拟机操作和替换的复杂性,因此不需要在夜间或周末没有人工作时间来测试新的硬件环境。当我们可以迅速启动一个实例的时候,为什么我们需要担心这个实例运行的环境?

  • 这就是为什么我们向云提供商支付很多费用的原因。当我们为实例放置数据库容器时,上面说的这些便利性就不存在了。因为数据不匹配,新实例不会与现有的实例兼容,如果要限制实例使用单机服务,应该让 DB 使用非容器化环境,我们仅仅需要为计算服务层保留弹性扩展的能力。

9.7 运行数据库的环境需求

  • 常看到 DBMS 容器和其他服务运行在同一主机上。然而这些服务对硬件要求是非常不同的。

  • 数据库(特别是关系型数据库)对 IO 的要求较高。一般数据库引擎为了避免并发资源竞争而使用专用环境。如果将你的数据库放在容器中,那么将浪费你的项目的资源。因为你需要为该实例配置大量额外的资源。在公有云,当你需要 34G 内存时,你启动的实例却必须开 64G 内存。在实践中,这些资源并未完全使用。

  • 怎么解决?您可以分层设计,并使用固定资源来启动不同层次的多个实例。水平伸缩总是比垂直伸缩更好。

9.8 总结

针对上面问题是不是说数据库一定不要部署在容器里吗?

答案是:并不是

我们可以把数据丢失不敏感的业务(搜索、埋点)就可以数据化,利用数据库分片来来增加实例数,从而增加吞吐量。

docker适合跑轻量级或分布式数据库,当docker服务挂掉,会自动启动新容器,而不是继续重启容器服务。

数据库利用中间件和容器化系统能够自动伸缩、容灾、切换、自带多个节点,也是可以进行容器化的。

1

评论区