深入探索数据库容器:连接、导航与差异分析

1. 连接到容器

连接容器类似于通过 SSH 连接远程主机。连接成功后,我们可以使用熟悉的 shell 命令来操作容器的操作系统,而且在容器中运行的命令不会影响本地环境。

使用 docker exec 命令连接容器, exec 代表执行,基本语法如下:

docker exec <CONTAINER NAME> <COMMAND>

其中,容器名称是目标容器,命令是容器中存在的任何可执行脚本或命令。若要在容器中启动交互式会话,可执行一个 shell,例如 bash

> docker exec -it ORCL bash
[oracle@8facfd649aa4 ~]$

对该命令的详细解析如下:
- -it 标志是向 Docker 传递多个标志的简写方式,分别代表 --interactive (-i) --tty (-t) ,它们结合使用可在为容器分配伪 TTY 或类似终端会话的同时保持标准输入(STDIN)打开,即实现交互式会话。标志顺序无关紧要,可以单独出现或组合使用,也可混合使用长标志和短标志。
- ORCL 是容器的名称。
- bash 是 Docker 在容器中运行的命令,它是许多 Linux 操作系统(包括 Oracle Enterprise Linux)的默认 shell。

Docker 返回的提示信息 [oracle@8facfd649aa4 ~]$ 显示了用户( oracle )、主机名( 8facfd649aa4 )和当前工作目录( ~ ,代表用户主目录)。虽然容器名称是 ORCL ,但主机名却是 8facfd649aa4 ,这其实是容器 ID。通过 docker ps 命令可以验证:

> docker ps
CONTAINER ID   IMAGE                       NAMES
8facfd649aa4   oracle/database:19.3.0-ee   ORCL

Docker 能识别我们分配的“友好”容器名称,在调用命令时,既可以使用容器 ID 也可以使用容器名称来引用容器。Docker 为容器创建唯一标识符并将其用作主机名,以避免因用户分配的名称可能违反主机命名约定而导致的问题。

此外,只要是镜像的一部分,也可以使用不同的 shell 登录容器,例如将 bash 替换为 sh

> docker exec -it ORCL sh
sh-4.2$

docker exec 是连接容器并在其中运行命令的主要方法。

2. 导航 Oracle 数据库容器

连接到数据库容器后,查看其环境,乍一看与在 Linux 上本地运行的典型数据库主机并无不同。以下是一些查询环境的基本命令及其结果:

[oracle@8facfd649aa4 ~]$ id
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),54322(dba),54323(oper),54324(backupdba),54325(dgdba),54326(kmdba),54330(racdba)
[oracle@8facfd649aa4 ~]$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.8 (Maipo)
[oracle@8facfd649aa4 ~]$ ps -ef | grep pmon | grep -v grep
oracle      2464       1  0 22:42 ?        00:00:00 ora_pmon_ORCLCDB
[oracle@8facfd649aa4 ~]$ egrep -v "^$|^#" /etc/oratab
ORCLCDB:/opt/oracle/product/19c/dbhome_1:N

这些结果表明这是一台运行 RHEL 7.8 的 Linux 机器,存在 oracle 用户和 Oracle 的 PMON 进程,并且 /etc/oratab 文件中有数据库条目,一切看起来都很正常。这体现了容器的神奇之处,在大多数情况下,它们与成熟的本地主机几乎没有区别。

3. 容器差异
3.1 主机名

尝试更改主机名时会发现一些差异。普通用户 oracle 无法更改主机名:

[oracle@8facfd649aa4 ~]$ hostname
8facfd649aa4
[oracle@8facfd649aa4 ~]$ cat /etc/hosts
127.0.0.1     localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0     ip6-mcastprefix
ff02::1     ip6-allnodes
ff02::2     ip6-allrouters
172.17.0.7     8facfd649aa4
[oracle@8facfd649aa4 ~]$ hostname ORCL
hostname: you must be root to change the host name

即使以 root 用户身份登录容器,也无法更改主机名:

> docker exec -it -u root ORCL bash
bash-4.2# whoami
root
bash-4.2# hostname ORCL
hostname: you must be root to change the hostname
3.2 cron

容器中的操作系统实际上只是一个包含必要二进制文件和库的文件系统,用于执行特定的有限任务。cron 是一种系统管理进程,在容器中查看包含“system”的进程:

[oracle@8facfd649aa4 ~]$ ps -ef | grep system
oracle     6486    4347  0 23:56 pts/0   00:00:00 grep --color=auto system

而在运行完整 Ubuntu Linux 操作系统的主机上查看包含“system”的进程:

> ps -ef | grep system
root         486       1  0 Feb14 ?        00:00:10 /lib/systemd/systemd-journald
root         520       1  0 Feb14 ?        00:00:14 /lib/systemd/systemd-udevd
systemd+     741       1  0 Feb14 ?        00:00:05 /lib/systemd/systemd-timesyncd
systemd+     750       1  0 Feb14 ?        00:00:10 /lib/systemd/systemd-networkd
systemd+     753       1  0 Feb14 ?        00:00:11 /lib/systemd/systemd-resolved
message+     792       1  0 Feb14 ?        00:00:32 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root         809       1  0 Feb14 ?        00:00:14 /lib/systemd/systemd-logind
root         812       1  0 Feb14 ?        00:04:09 /usr/sbin/thermald --systemd --dbus-enable --adaptive
lab       744954       1  0 Feb26 ?        00:01:05 /lib/systemd/systemd --user
lab      2348206 2334483  0 23:56 pts/6    00:00:00 grep --color=auto system

可以看出容器中没有系统进程,包括运行 cron 所需的进程。不过, crontab 命令存在, oracle 用户可以运行它。尝试编辑 crontab 时:

[oracle@8facfd649aa4 ~]$ crontab -l
no crontab for oracle
[oracle@8facfd649aa4 ~]$ crontab -e
no crontab for oracle - using an empty one
/bin/sh: /usr/bin/vi: No such file or directory
crontab: "/usr/bin/vi" exited with status 127

这是因为 vi 编辑器缺失。以 root 用户身份登录容器并使用 yum 安装 vi

> docker exec -it -u root ORCL bash
bash-4.2# yum install -y vi
Loaded plugins: ovl
ol7_latest                            | 3.6 kB  00:00:00
(1/3): ol7_latest/x86_64/group_gz     | 136 kB  00:00:00
(2/3): ol7_latest/x86_64/updateinfo   | 3.4 MB  00:00:03
(3/3): ol7_latest/x86_64/primary_db   |  39 MB  00:00:08
Resolving Dependencies
--> Running transaction check
---> Package vim-minimal.x86_64 2:7.4.629-8.0.1.el7_9 will be installed
--> Finished Dependency Resolution
...
Install  1 Package
Total download size: 443 k
...
Installed:
  vim-minimal.x86_64 2:7.4.629-8.0.1.el7_9
Complete!

安装 vi 后,添加 cron 任务:

* * * * * touch /home/oracle/added_by_cron

检查 oracle 用户的 crontab,任务已存在,但实际上该文件并未按预期创建:

[oracle@8facfd649aa4 ~]$ crontab -l
* * * * * touch /home/oracle/added_by_cron
[oracle@8facfd649aa4 ~]$ date
Mon Jan  7 00:10:01 UTC 2022
[oracle@8facfd649aa4 ~]$ ls -l /home/oracle
total 0
lrwxrwxrwx 1 root root 26 Apr 10  2021 setPassword.sh -> /opt/oracle/setPassword.sh
[oracle@8facfd649aa4 ~]$ date
Mon Jan  7 00:44:26 UTC 2022
[oracle@8facfd649aa4 ~]$ ls -l /home/oracle
total 0
lrwxrwxrwx 1 root root 26 Apr 10  2021 setPassword.sh -> /opt/oracle/setPassword.sh

返回 root 会话检查并尝试启动 cron 服务,会失败:

bash-4.2# service crond status
Redirecting to /bin/systemctl status crond.service
Failed to get D-Bus connection: Operation not permitted
bash-4.2# service crond start
Redirecting to /bin/systemctl start crond.service
Failed to get D-Bus connection: Operation not permitted

这是因为 cron 是系统进程,容器期望主机操作系统来处理,容器中没有运行的系统进程来识别和运行任务。对于依赖 init.d 或 system.d 的 Oracle 数据库相关产品,如 Oracle Grid Infrastructure、Oracle Real Application Clusters 和 Oracle Restart,在容器中的运行会存在问题,但也有方法为容器添加此功能。

3.3 二进制文件

容器通常大规模部署,较小的容器可最大化基础设施容量,且在网络中复制所需时间更短。构建容器镜像时,目标是消除不必要的内容,像 vi 这样的编辑器就不是必需的。

在容器中修改文件并非常见操作,因为容器镜像提供的是现成的文件系统,用于执行特定服务或功能,而非多功能交互式系统。如果需要编辑文件,通常在构建镜像时完成并嵌入其中,而不是在容器运行后进行。若需要修改容器中的文件,自动化友好的编辑器(如 sed )更合适。

此外,容器中缺少的二进制文件和工具不仅限于编辑器,任何不必要的软件都会增加攻击面,限制容器上安装的软件可减少攻击者可利用的资源,这也是容器与物理或虚拟主机的另一个区别。Docker 的 Linux 发行版通常有“-slim”选项,表示是精简版,但不同供应商和版本对于精简版包含或排除的内容没有统一标准。生产环境中常用的镜像通常从精简版开始,再添加必要的内容。对于大多数人来说,将数据库放入容器的初始用例可能涉及一些交互,因此需要编辑器和诊断工具,好在修改构建脚本以包含二进制文件并不困难。

下面用 mermaid 流程图展示容器操作的部分流程:

graph TD;
    A[开始] --> B[连接到容器: docker exec -it ORCL bash];
    B --> C[查看容器环境信息];
    C --> D{是否需要修改文件};
    D -- 是 --> E[检查是否有编辑器];
    E -- 无 --> F[以 root 身份安装编辑器: docker exec -it -u root ORCL bash 并 yum install -y vi];
    F --> G[编辑文件];
    D -- 否 --> H[进行其他操作];
    C --> I{是否需要设置 cron 任务};
    I -- 是 --> J[检查 cron 服务状态];
    J -- 未运行 --> K[尝试启动 cron 服务: service crond start];
    K --> L[添加 cron 任务];
    I -- 否 --> H;
4. Oracle 目录

Oracle 容器注册表镜像中,一些 Oracle 特定文件的位置存在差异。进入 ORACLE_BASE 目录并列出其内容:

[oracle@8facfd649aa4 opt]$ cd $ORACLE_BASE
[oracle@8facfd649aa4 oracle]$ pwd
/opt/oracle
[oracle@8facfd649aa4 oracle]$ ls -l
total 92
drwxr-x--- 3 oracle oinstall 4096 Mar  6 22:04 admin
drwxr-x--- 2 oracle oinstall 4096 Mar  6 22:04 audit
drwxr-x--- 4 oracle oinstall 4096 Mar  6 22:15 cfgtoollogs
-rwxrwxr-x 1 oracle dba      1040 Mar 31  2021 checkDBStatus.sh
drwxr-xr-x 2 oracle dba      4096 Apr 10  2021 checkpoints
-rwxrwxr-x 1 oracle dba      4121 Mar 31  2021 createDB.sh
-rw-rw-r-- 1 oracle dba      9204 Oct 11  2020 dbca.rsp.tmpl
drwxrwxr-x 1 oracle dba      4096 Apr 10  2021 diag
drwxrwx--- 1 oracle dba      4096 Mar  6 23:32 oraInventory
drwxr-xr-x 1 oracle dba      4096 Mar  6 23:33 oradata
drwxr-xr-x 1 oracle dba      4096 Apr 10  2021 product
-rwxrwxr-- 1 oracle dba      1941 Oct 11  2020 relinkOracleBinary.sh
-rwxrwxr-x 1 oracle dba      6488 Mar 31  2021 runOracle.sh
-rwxrwxr-x 1 oracle dba      1015 Oct 11  2020 runUserScripts.sh
drwxr-xr-x 1 oracle dba      4096 Apr 10  2021 scripts
-rwxrwxr-x 1 oracle dba       758 Oct 11  2020 setPassword.sh
-rwxrwxr-x 1 oracle dba       678 Oct 11  2020 startDB.sh

大部分目录是预期中的,如 admin audit diagnostic 目录,以及 product 目录(构成系统上安装的 ORACLE_HOME 的根目录)和 oradata 目录(Oracle 存储数据库文件的地方)。但 oraInventory 目录通常不建议安装在 ORACLE_BASE 内,这与容器使用联合文件系统以提高效率有关。

5. 配置文件

进入 ORACLE_BASE/oradata 目录,会发现两个子目录 ORCLCDB dbconfig

[oracle@8facfd649aa4 oradata]$ pwd
/opt/oracle/oradata
[oracle@8facfd649aa4 oradata]$ ls -l
total 8
drwxr-x--- 4 oracle oinstall 4096 Mar  6 22:15 ORCLCDB
drwxr-xr-x 3 oracle oinstall 4096 Mar  6 23:33 dbconfig

列出 ORCLCDB 子目录的内容:

[oracle@8facfd649aa4 oradata]$ ls -l ORCLCDB
total 2341684
drwxr-x--- 2 oracle oinstall      4096 Mar  6 23:32 ORCLPDB1
-rw-r----- 1 oracle oinstall  18726912 Mar  7 01:44 control01.ctl
-rw-r----- 1 oracle oinstall  18726912 Mar  7 01:44 control02.ctl
drwxr-x--- 2 oracle oinstall      4096 Mar  6 22:37 pdbseed
-rw-r----- 1 oracle oinstall 209715712 Mar  7 00:38 redo01.log
-rw-r----- 1 oracle oinstall 209715712 Mar  7 01:44 redo02.log
-rw-r----- 1 oracle oinstall 209715712 Mar  6 23:32 redo03.log
-rw-r----- 1 oracle oinstall 545267712 Mar  7 01:41 sysaux01.dbf
-rw-r----- 1 oracle oinstall 933240832 Mar  7 01:41 system01.dbf
-rw-r----- 1 oracle oinstall  33562624 Mar  6 22:44 temp01.dbf
-rw-r----- 1 oracle oinstall 246423552 Mar  7 01:43 undotbs01.dbf
-rw-r----- 1 oracle oinstall   5251072 Mar  7 00:43 users01.dbf

这与非容器环境中的 Oracle 数据库安装一致。而 dbconfig 目录则出乎意料,其内容如下:

[oracle@8facfd649aa4 oradata]$ ls -l dbconfig
total 4
drwxr-xr-x 2 oracle oinstall 4096 Mar  6 23:33 ORCLCDB
[oracle@8facfd649aa4 oradata]$ ls -l dbconfig/ORCLCDB
total 24
-rw-r--r-- 1 oracle oinstall  234 Mar  6 22:04 listener.ora
-rw-r----- 1 oracle oinstall 2048 Mar  6 22:15 orapwORCLCDB
-rw-r--r-- 1 oracle oinstall  784 Mar  6 23:33 oratab
-rw-r----- 1 oracle oinstall 3584 Mar  6 23:33 spfileORCLCDB.ora
-rw-r--r-- 1 oracle oinstall   53 Mar  6 22:04 sqlnet.ora
-rw-r----- 1 oracle oinstall  211 Mar  6 23:33 tnsnames.ora

这些配置文件通常保存在 ORACLE_HOME /etc 下。实际上,网络配置文件 listener.ora sqlnet.ora tnsnames.ora ORACLE_HOME/network/admin 目录下的文件链接到了 ORACLE_BASE/oradata/dbconfig/ORCLCDB 中的文件:

[oracle@8facfd649aa4 oradata]$ ls -l $ORACLE_HOME/network/admin
total 8
lrwxrwxrwx 1 oracle oinstall   49 Mar  6 23:33 listener.ora -> /opt/oracle/oradata/dbconfig/ORCLCDB/listener.ora
drwxr-xr-x 2 oracle dba      4096 Apr 17  2019 samples
-rw-r--r-- 1 oracle dba      1536 Feb 14  2018 shrept.lst
lrwxrwxrwx 1 oracle oinstall   47 Mar  6 23:33 sqlnet.ora -> /opt/oracle/oradata/dbconfig/ORCLCDB/sqlnet.ora
lrwxrwxrwx 1 oracle oinstall   49 Mar  6 23:33 tnsnames.ora -> /opt/oracle/oradata/dbconfig/ORCLCDB/tnsnames.ora

密码文件 orapwORCLCDB 和服务器参数文件 spfileORCLCDB.ora ORACLE_HOME/dbs 中的文件也链接到了 ORACLE_BASE/oradata/dbconfig/ORCLCDB 中的文件:

[oracle@8facfd649aa4 oradata]$ ls -l $ORACLE_HOME/dbs
total 12
-rw-rw---- 1 oracle oinstall 1544 Mar  6 23:32 hc_ORCLCDB.dat
-rw-r--r-- 1 oracle dba      3079 May 14  2015 init.ora
-rw-r----- 1 oracle oinstall   24 Mar  6 22:10 lkORCLCDB
lrwxrwxrwx 1 oracle oinstall   49 Mar  6 23:33 orapwORCLCDB -> /opt/oracle/oradata/dbconfig/ORCLCDB/orapwORCLCDB
lrwxrwxrwx 1 oracle oinstall   54 Mar  6 23:33 spfileORCLCDB.ora -> /opt/oracle/oradata/dbconfig/ORCLCDB/spfileORCLCDB.ora

/etc/oratab 文件与 ORACLE_BASE/oradata/dbconfig/ORCLCDB/oratab 文件内容相同:

[oracle@8facfd649aa4 oradata]$ ls -l /etc/oratab
-rw-rw-r-- 1 oracle oinstall 784 Mar  6 23:33 /etc/oratab
[oracle@8facfd649aa4 oradata]$ md5sum /etc/oratab
31f3633542a9883ebd7f0eaac771ec7b  /etc/oratab
[oracle@8facfd649aa4 oradata]$ md5sum $ORACLE_BASE/oradata/dbconfig/ORCLCDB/oratab
31f3633542a9883ebd7f0eaac771ec7b  /opt/oracle/oradata/dbconfig/ORCLCDB/oratab

综上所述,在使用数据库容器时,需要了解这些差异,以便更好地进行管理和维护。例如,对于主机名和 cron 服务的限制,要寻找合适的解决方案;对于二进制文件的精简,要根据实际需求调整镜像构建;对于 Oracle 目录和配置文件的特殊位置,要清楚其原理和影响。

深入探索数据库容器:连接、导航与差异分析

6. 差异总结与应对策略

为了更清晰地了解容器与传统主机的差异,我们将上述差异点总结成以下表格:
|差异点|具体表现|影响|应对策略|
| ---- | ---- | ---- | ---- |
|主机名|普通用户和 root 用户均无法更改主机名|可能影响系统管理和网络配置|目前暂无直接解决办法,但可通过其他方式(如修改外部网络配置)进行弥补|
|cron|容器中无运行的系统进程来识别和运行 cron 任务,即便安装了必要工具,cron 任务也无法正常执行|影响定时任务的执行,如数据库备份等|有方法为容器添加此功能,需进一步探索合适的解决方案|
|二进制文件|容器镜像中通常去除不必要的二进制文件,如编辑器|修改文件不便,增加攻击面|修改构建脚本以包含必要的二进制文件,使用自动化友好的编辑器(如 sed )|
|Oracle 目录| oraInventory 目录出现在 ORACLE_BASE 内|与 Oracle 安装建议不符,可能影响数据库管理|了解其与容器使用联合文件系统的关系,在管理时注意该目录的特殊性|
|配置文件|配置文件存于 ORACLE_BASE/oradata/dbconfig 目录,而非传统的 ORACLE_HOME /etc |可能导致配置管理混乱|清楚配置文件的链接关系,在修改配置时注意文件的实际位置|

7. 容器操作最佳实践

结合上述差异和分析,以下是一些在使用数据库容器时的最佳实践:
1. 连接容器 :使用 docker exec 命令连接容器,确保正确传递 -it 标志以实现交互式会话。若需要以不同用户身份登录,可使用 -u 标志。
2. 环境检查 :连接到容器后,使用基本命令(如 id cat /etc/redhat-release 等)检查容器环境,确保其符合预期。
3. 文件修改 :尽量在构建镜像时完成文件的编辑,避免在容器运行后进行修改。若必须修改,优先使用自动化友好的编辑器(如 sed )。
4. cron 任务 :在设置 cron 任务前,确保容器中有运行的 cron 服务。若没有,可尝试为容器添加此功能或寻找替代方案。
5. 配置管理 :了解 Oracle 配置文件的特殊位置,在修改配置时注意文件的链接关系,避免因配置错误导致数据库故障。

8. 未来展望

随着容器技术的不断发展,数据库容器的应用将越来越广泛。未来,可能会有更多的工具和方法来解决容器中存在的问题,如更好地支持系统管理进程(如 cron)、更灵活的主机名配置等。同时,容器镜像的构建和管理也将更加智能化和自动化,为用户提供更便捷的使用体验。

下面用 mermaid 流程图展示容器操作的整体最佳实践流程:

graph TD;
    A[开始] --> B[连接到容器: docker exec -it ORCL bash];
    B --> C[检查容器环境信息];
    C --> D{是否需要修改文件};
    D -- 是 --> E[使用自动化友好编辑器(如 sed)修改];
    E --> F[保存修改];
    D -- 否 --> G{是否需要设置 cron 任务};
    G -- 是 --> H[检查 cron 服务状态];
    H -- 未运行 --> I[添加 cron 功能或寻找替代方案];
    I --> J[添加 cron 任务];
    G -- 否 --> K{是否需要修改配置文件};
    K -- 是 --> L[了解配置文件位置和链接关系];
    L --> M[修改配置文件];
    K -- 否 --> N[进行其他操作];
    F --> N;
    J --> N;
    M --> N;
    N --> O[结束];
9. 总结

数据库容器为数据库管理带来了新的方式和挑战。通过深入了解容器与传统主机的差异,我们可以更好地管理和维护数据库容器。在实际应用中,要根据具体需求和场景,灵活运用上述知识和最佳实践,确保数据库容器的稳定运行。同时,关注容器技术的发展趋势,不断学习和探索新的解决方案,以适应不断变化的技术环境。

希望本文能为你在使用数据库容器时提供有价值的参考,让你更加从容地应对各种问题。如果你在实践过程中有任何疑问或经验分享,欢迎在评论区留言交流。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐