Docker初探与安装基于docker的mysql-server服务

由于工作需要,我要在一个docker环境中安装一个mysql,于是对docker和mysql做了一点探究,笔记如下。

零、背景知识

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

简单来说,Docker将应用程序及其运行环境(包括操作系统、库、配置 等)封装在一个独立的、可移植的“容器”中。这个容器可以在任何支持Docker的平台上运行,无需关心底层的操作系统或硬件差异。这使得开发者可以更加专注于代码开发,而不用担心环境配置的问题,同时也简化 了部署和运维过程。

Docker的核心组件包括镜像(Image)、容器(Container)和仓库(Repository)。镜像是创建容器的基础,它包含了应用程序的所有依赖;容器是从镜像创建的一个运行实例;仓库则是用来存储和分发镜像的地方 。

Docker改变了软件的交付方式,使得开发、测试、部署变得更加高效和 一致。其logo是一条托着一堆集装箱的鲸鱼,更是展示出其包容一切、托付一切的美好愿景。

一、基本概念

在Docker技术中,有一些基本概念需要辨析一下:

  1. 镜像(Image):Docker镜像是一个只读模板,包含了应用程序 的代码、运行时依赖(比如库、配置文件等),以及运行时的环境。它 是构建容器的基础,类似于软件包(安装包)或安装系统所需的ISO镜像。每个镜像都有一个唯一的ID,并且可以通过命令行工具如docker pull从Docker Hub等仓库下载,或者通过docker build自己创建。
  2. 仓库(Repository):仓库是存储Docker镜像的地方,可以是私有的(如Docker Hub上的个人账户)或公共的(如Docker Hub、GitHub Container Registry等)。用户可以从仓库下载镜像,也可以将自己的 镜像上传到仓库分享给其他人。
  3. 容器(Container):容器是镜像的运行实例(Instance)。当你基于一个镜 像启动一个容器时,系统会创建一个新的进程空间,与宿主机隔离,但 共享内核。容器有自己的文件系统、网络设置和端口映射,但不包含宿 主机的文件系统,这使得容器之间互相独立,易于管理和复制(这听起来很像虚拟机,但docker允许容器和宿主机共享内核,不需要对硬件进行模拟,因此其计算开销要远小于虚拟机技术)。docker允许在同一台宿主机上基于同一个镜像启动多个容器,每个容器都是该镜像的一个实例。

关于docker的虚拟化(Virtualization),这里做一点补充。虚拟化是一种技术,允许一台物理计算机同时运行多个独立的操作系统实例;Docker使用的是轻量级虚拟 化,也称为容器虚拟化,它不是在底层创建完整的虚拟机,而是利用操 作系统提供的资源隔离(如命名空间和控制组)来创建容器,从而节省 资源并提高效率。

一句话总结:镜像是docker的基础,仓库是存储docker镜像的地方,容器是镜像的运行实例,而虚拟化是实现容器化的一种技术。

二、安装

这一部分另外参见 Docker的官方文档

docker的运行需要Linux系统内核,因此在Linux系统上的安装很方便,而在macOS和Windows上则需要一些额外的步骤。

(一)在Linux主流发行版上安装docker-engine

参考:

docker-engine是docker中最核心的组件,用于容器的管理与运行。在Linux的几大主流发行版上均可通过下面的方法安装docker-engine,但同样也可以安装docker官方提供的docker-desktop,后者是一个可视化的docker安装和管理工具。

下面我们介绍docker-engine的安装。

在Redhat Enterprise Linux(RHEL)、centOS、Alibaba cloud Linux等红帽系发行版上,使用下面的步骤即可进行安装:

1
2
3
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf makecache
sudo dnf install docker-ce docker-ce-cli containerd.io

上述三条指令分别用于添加docker社区版的软件包仓库、更新软件包列表缓存,以及进行docker安装。dnf是红帽系发行版中较新采用的一个包管理器,如果要使用旧版的yum包管理器,可以使用下面的方法:

1
2
3
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

在Debian、Ubuntu等deb系发行版上,使用下面的步骤进行安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# update apt-get list
sudo apt-get update
# and install
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

(二)macOS安装docker-desktop

参考: Docker.docs - Install Docker Desktop on Mac

首先,从docker官网下载最新版本的docker desktop安装包。随后双击安装包,根据提示完成安装和配置(一般情况下使用默认配置即可),即可完成安装。

(三)windows安装docker-desktop

参考:Docker.docs - Install Docker Desktop on Windows

由于Windows的内核与Linux/Unix那一套相去甚远,按理说Windows原生是不支持docker的。不过好在windows支持hyper-V这种半虚拟化技术(需要硬件支持),且前几年微软推出了一个大杀器——windows subsystem for linux(wsl),使得在Windows上运行Linux程序成为可能,于是docker也就顺理成章能够在Windows上运行了。

因此,要在Windows上安装docker,首先需要开启系统的WSL2功能,或开启hyper-V虚拟化功能。随后,从docker官网下载最新版安装包,并双击安装即可。

三、初识docker

下面以linux系统为例,简单展示一下docker的一些基本操作:

  • docker images : 列出本地主机上的所有镜像
  • docker search : 从Docker Hub中搜索镜像
  • docker pull : 从Docker Hub下载镜像到本地
  • docker system df : 显示Docker磁盘使用情况
  • docker rmi : 删除本地的一个或多个 镜像
  • docker rm : 删除一个或多个 容器
  • docker commit : 从正在运行的容器创建一个新的镜像
  • docker build : 根据Dockerfile构建镜像
  • docker run : 创建一个新的容器并运行一个命令
  • docker ps : 列出当前正在运行的容器
  • docker exec -it <container ID/name> bashShell : 在正在运行的容器中执行命令
  • docker attach <container ID> : 连接到正在运行中的容器
  • docker start : 启动一个或多个已经被停止的容器
  • docker stop : 停止运行中的容器
  • docker restart : 重启容器

一个简单的示例:

1
2
3
sudo docker search hello-world # 查询名叫hello-world的镜像。这个镜像是docker中很著名的测试镜像
sudo docker pull hello-world # 将上述镜像下载到本地
sudo docker run hello-world # 基于上述镜像运行一个容器

运行效果如下:

四、使用docker安装mysql-server

由于我在公共服务器上没有root权限,无法使用正常的方式安装mysql-server,因此只能使用docker曲线救国。下面是探索的结果:

首先,从dockerhub上拉取镜像:

1
2
3
docker search mysql
docker pull mysql:5.7 # 从docker仓库中拉取mysql的基础镜像
docker images # 列出已经下载的容器列表

终端输出如下:

1
2
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
mysql 5.7 5107333e08a8 5 months ago 501MB

在拉取完镜像以后,我们基于这个镜像启动一个容器实例。由于mysql-server需要容器和宿主机之间的双向通信,我们的启动脚本会稍微有些复杂,如下(可以写到一个shell脚本里面,然后以脚本的方式运行):

1
2
3
4
5
6
7
#!/bin/bash
docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-u $(id -u):$(id -g) \
-d mysql:5.7

顺便解释一下上面的这些参数:

  • -p用于配置网络端口映射,上面的写法是将宿主机的3306端口映射到容器的3306端口。
  • --name用于指定这个容器的名称。如果不指定,则docker会随机生成一个name(一般是一个形容词+一个名词的格式,其实抛开实用性不谈,docker随机生成的name还挺好玩,例如great_noethermodest_borgfrosty_germainsleepy_elion等等)
  • -v用于将宿主机中的目录(冒号前)挂在到容器中(冒号后)。挂载的目录必须是普通用户有访问权限的目录(最好提前创建,否则后期改权限很麻烦),并且不可以是软链接目录。
  • -e配置运行时的环境变量,对于mysql-server来说,需要配置的环境变量只有root密码这一个。
  • -u指定使用特定用户身份登录。默认情况下会以root身份登录,但实际使用时可能会有 chown: changing ownership of '/var/lib/mysql/': Operation not permitted 的访问权限问题。因此这里需要指定登录身份。
  • -d表明让这个docker容器后台运行,就像一个服务程序那样。

运行上面的指令可以让mysql服务在后台运行。可以使用docker ps -a查看服务状态:

(注意,一些停止运行的容器也会被列出)

要暂停这个容器,可以使用docker stop <container ID/name>指令。要彻底删除这个容器,可以使用docker rm <container ID/name>

我们也可以登录到这个容器内部看一看:

1
docker exec -it mysql bash

上面这串指令的意思是在mysql容器中,以交互式的方式(由参数-it控制)运行bash指令。效果如下:

五、宿主机mysql客户端连接容器内的mysql服务端

最后,我们看一下如何在宿主机中连接这个数据库。在宿主机中使用下面的命令即可登录(其中,-h指定mysql-server的IP地址,此处为本地即127.0.0.1(不设置这个参数的话,mysql客户端会去找套接字文件/tmp/mysql.sock,从而引发一些报错);-P指定端口,此处为前面使用的3306;-p指定使用交互式密码输入界面登录数据库)

1
mysql -h 127.0.0.1 -P 3306 -u root -p 

登陆界面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(base) cyclin@iZf8z0u1kbopnpeuu32nf5Z:~/miniconda3/pkgs/mysql-connector-python-8.3.0-py310h1b8f574_0$ mysql -h 127.0.0.1 -P 3306 -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.44 MySQL Community Server (GPL)

Copyright (c) 2000, 2024, 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>

如果连接失败,可以尝试检查防火墙设置。在ubuntu系统上,防火墙的设置如下

1
sudo ufw allow 3306/tcp # 允许3306端口的TCP连接

关于端口占用情况:前面的启动脚本中 指定了使用宿主机3306端口作为mysql-server的服务端口。然而在公共计算平台上,我们无法保证这一端口没有被其他人使用。因此,在启动docker前,检查端口占用情况也是很重要的。

下面是一些检查端口占用情况的指令:

1
2
netstat -tuln # 检查已用端口有哪些
lsof -i :3306 # 查看占用某端口(以3306端口为例)的具体进程有哪些

运行示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(base) [zhangwanyu@lih005]~$  netstat -tuln |head
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:9028 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:9029 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:34055 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:40040 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:16554 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:3690 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:44171 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:9005 0.0.0.0:* LISTEN
(base) [zhangwanyu@lih005]~$ lsof -i :45012
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 27890 zhangwanyu 18u IPv4 216467048 0t0 TCP localhost:45012 (LISTEN)
node 27890 zhangwanyu 21u IPv4 216467050 0t0 TCP localhost:45012->localhost:39406 (CLOSE_WAIT)

以上。