系统初始化

本次作为测试安装,我这里使用的是一台虚拟机,具体配置如下:

主机名 IP 地址 系统版本 内存(G) CPU(核) 硬盘(G)
node-01 192.168.200.101 CentOS Linux release 7.9.2009 4 4 20
  1. 关闭防火墙和 Selinux
1
2
3
4
5
6
7
8
9
10
11
12
# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

# 关闭 Selinux
sed -i "s#^SELINUX=.*#SELINUX=disabled#g" /etc/selinux/config
setenforce 0

# 关闭 swap 分区
swapoff -a && sysctl -w vm.swappiness=0
sed -ri '/^[^#]*swap/s@^@#@' /etc/fstab

  1. 配置 yum 源(云服务器不需要)
1
2
3
4
5
6
7
# 备份旧的 yum 源
cd /etc/yum.repos.d/
mkdir backup-$(date +%F)
mv *repo backup-$(date +%F)

# 添加阿里云 yum 源
curl http://mirrors.aliyun.com/repo/Centos-7.repo -o ali.repo
  1. 安装基础依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 安装 epel 源
yum -y install epel-release
yum clean all
yum makecache

# 安装常用依赖
yum -y install gcc glibc gcc-c++ make cmake net-tools screen vim lrzsz tree dos2unix lsof \
tcpdump bash-completion wget ntp setuptool openssl openssl-devel bind-utils traceroute \
bash-completion bash-completion-extras glib2 glib2-devel unzip bzip2 bzip2-devel libevent libevent-devel \
ntp expect pcre pcre-devel zlib zlib-devel jq psmisc tcping yum-utils device-mapper-persistent-data \
lvm2 git device-mapper-persistent-data bridge-utils container-selinux binutils-devel \
ncurses ncurses-devel elfutils-libelf-devel

# 升级服务器
yum update
  1. 时间同步
1
2
echo "# 互联网时间同步" >> /var/spool/cron/root
echo "*/5 * * * * /usr/sbin/ntpdate time2.aliyun.com >/dev/null 2>&1" >> /var/spool/cron/root
  1. 打开文件数优化
1
2
3
4
5
6
7
8
9
cat >> /etc/security/limits.conf << EOF
# 打开文件优化配置
* soft nofile 655360
* hard nofile 131072
* soft nproc 655350
* hard nproc 655350
* soft memlock unlimited
* hard memlock unlimited
EOF
  1. 内核优化
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
cat >> /etc/sysctl.d/user.conf << EOF
# 内核调优
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
fs.may_detach_mounts = 1
vm.overcommit_memory=1
vm.panic_on_oom=0
fs.inotify.max_user_watches=89100
fs.file-max=52706963
fs.nr_open=52706963
net.netfilter.nf_conntrack_max=2310720
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl =15
net.ipv4.tcp_max_tw_buckets = 36000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_orphans = 327680
net.ipv4.tcp_orphan_retries = 3
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.ip_conntrack_max = 65536
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_timestamps = 0
net.core.somaxconn = 16384
EOF
  1. 内核升级

docker 对于 CentOS 的要求为内核版本不低于 3.10,尽管 7.9 已经是 3.10 版本,但还是有升级的必要。

同时作为生产环境,一般不会选择安装最新版本。但官方仓库中提供的 rpm 一般只会有一个 lt 和一个 ml 版本,所以需要从第三方下载想要的版本,统一服务器的内核版本,可以避免出现未知 BUG。

http://193.49.22.109/elrepo/kernel/el7/x86_64/RPMS/

本次使用的是 4 版本最后一版:4.20

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 下载内核 rpm 包
cd /usr/local/src/
wget http://193.49.22.109/elrepo/kernel/el7/x86_64/RPMS/kernel-ml-4.20.13-1.el7.elrepo.x86_64.rpm
wget http://193.49.22.109/elrepo/kernel/el7/x86_64/RPMS/kernel-ml-devel-4.20.13-1.el7.elrepo.x86_64.rpm

# 安装内核
yum -y localinstall kernel-ml-*

# 查看顺序
awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg

# 设置默认启动内核,上面的命令可以看到最新内核的序号是 0
grub2-set-default 0

# 重启系统
reboot

系统启动完成之后,查看内核情况:

1
uname -r

到此,系统初始化完成!

安装包准备

docker 目前有三种版本可供选择:nightly(开发版)test(测试版)stable(稳定版)

对于生产环境,为了避免因为版本不同导致集群出现未知 BUG,建议手动下载 rpm 包安装。本次安装版本为 20.10.9,下载地址:

https://download.docker.com/linux/centos/7/x86_64/stable/Packages/

如果觉得下载慢,可以使用国内的镜像地址:

http://mirrors.ustc.edu.cn/docker-ce/linux/centos/7/x86_64/stable/Packages/

需要下载的安装包如下:

  1. docker-ce-20.10.9-3.el7.x86_64.rpm(docker 引擎)
  2. docker-ce-cli-20.10.9-3.el7.x86_64.rpm(docker 引擎的命令行)
  3. containerd.io-1.6.6-3.1.el7.x86_64.rpm(守护进程,独立于 docker 工作,管理容器的生命周期)
  4. docker-ce-rootless-extras-20.10.9-3.el7.x86_64.rpm(ce 需要的依赖)
  5. docker-scan-plugin-0.9.0-3.el7.x86_64.rpm(cli 需要的依赖)

服务安装

事先使用 lrzsz 将下载的安装包上传到 /usr/local/src/ 目录然后开始进行安装。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 卸载可能存在的旧版本 docker
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

# 安装新版本
cd /usr/local/src/
yum -y localinstall docker* containerd*

# 启动 docker
systemctl start docker
systemctl enable docker
systemctl status docker

查看 docker 信息:

1
docker version

结果如下:

服务优化

由于 docker 默认的 registry 是 docker hub,而 docker hub 又是外网的服务,可能因为网络原因访问,下载都会非常慢。所以需要将 registry 调整为国内的。

国内常用的 registry 有以下一些:

  • 阿里云(需要注册用户):https://<你的ID>.mirror.aliyuncs.com
  • 网易:http://hub-mirror.c.163.com
  • 中科大:https://docker.mirrors.ustc.edu.cn

通过增加配置来修改 docker 默认的 registry 地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 创建 docker 数据目录
mkdir -p /ops/{data,service,log,backup,shell,package}
mkdir -p /ops/data/docker/{run,lib}

# 修改配置文件
# exec-opts:调整 docker 为 systemd 管理
# registry-mirrors:设置注册点
# bip:修改 docker 的网段
# exec-root:重新定义 docker 的运行目录
# data-root:重新定义 docker 的数据目录
cat > /etc/docker/daemon.json << EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"],
"bip": "172.16.0.1/16",
"exec-root": "/ops/data/docker/run",
"data-root": "/ops/data/docker/lib"
}
EOF

# 重启 docker
systemctl stop docker
systemctl start docker
systemctl status docker

如果不清楚网段划分,可以使用工具查看:

http://tools.jb51.net/aideddesign/ip_net_calc/

重启完成后查看 docker 信息:

1
docker info

如图所示:

故障排查

docker 在停止的时候可能会出现提醒:

Warning: Stopping docker.service, but it can still be activated by: docker.socket

告警的意思为:如果你试图连接到 docker socket,而 docker 服务没有运行,系统将自动启动 docker。

该配置是在 /lib/systemd/system/docker.service 中配置的:

1
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

所以这个告警可以忽略掉。

重启失败,大概可能是 /etc/docker/daemon.json 存在报错,可以通过错误日志查看信息:

1
tail -1000f /var/log/messages
  • 故障问题 1

unable to configure the Docker daemon with file /etc/docker/daemon.json: invalid character ‘Â’ looking for beginning of value

查看配置文件没有问题,但是一直这个错误,所以我怀疑里面的 tab 或者空格存在问题,通过执行命令:

1
cat -A /etc/docker/daemon.json

发现文件中确实有很多特殊的字符,因为配置是网上复制的。通过将里面空格和 tab 替换成空格之后故障解决。

  • 故障问题 2

unable to configure the Docker daemon with file /etc/docker/daemon.json: invalid character ‘}’ looking for beginning of object key string

原因是我在 json 最后一个值后面也加了 , 符号的缘故,删除了就好了。

daemon.json

配置文件 daemon.json 参数详解:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
{
// 在引擎 API 中设置 CORS 标头
"api-cors-header": "",
// 要加载的授权插件
"authorization-plugins": [],
// 将容器附加到网桥
"bridge": "",
// 指定网桥 IP
"bip": "192.168.88.0/22",
// 为所有容器设置父 cgroup
"cgroup-parent": "",
// 分布式存储后端的 URL
"cluster-store": "",
// 设置集群存储选项(默认map [])
"cluster-store-opts": {},
// 要通告的地址或接口名称
"cluster-advertise": "",
// 启用调试模式,启用后,可以看到很多的启动信息。默认 false
"debug": true,
// 容器默认网关 IPv4 地址
"default-gateway": "",
// 容器默认网关 IPv6 地址
"default-gateway-v6": "",
// 容器的默认 OCI 运行时,默认为 runc
"default-runtime": "runc",
// 容器的默认 ulimit(默认[])
"default-ulimits": {},
// 设定容器 DNS 的地址,在容器的 /etc/resolv.conf 文件中可查看
"dns": ["192.168.1.1"],
// 容器 /etc/resolv.conf 文件,其他设置
"dns-opts": [],
// 设定容器的搜索域。
"dns-search": [],
// 运行时执行选项
"exec-opts": [],
// 执行状态文件的根目录,默认 /var/run/docker
"exec-root": "",
// 固定 IP 的 IPv4 子网
"fixed-cidr": "",
// 固定 IP 的 IPv6 子网
"fixed-cidr-v6": "",
// docker 运行时使用的根路径,默认 /var/lib/docker
"data-root": "/var/lib/docker",
// UNIX 接字的组,默认 docker
"group": "",
// 设置容器 hosts
"hosts": [],
// 启用容器间通信,默认 true
"icc": false,
// 绑定容器端口时的默认 IP,默认 0.0.0.0
"ip": "0.0.0.0",
// 启用 iptables 规则添加,默认 true
"iptables": false,
// 启用IPv6网络
"ipv6": false,
// 默认 true, 启用 net.ipv4.ip_forward
"ip-forward": false,
// 启用 IP 伪装,默认 true
"ip-masq": false,
// 设置私有仓库地址可以设为 http
"insecure-registries": ["120.123.122.123:12312"],
// docker 主机的标签
"labels": ["nodeName=node-101"],
// 在容器仍在运行时启用 docker 的实时还原
"live-restore": true,
// 容器日志的默认驱动程序,默认 json-file
"log-driver": "",
// 设置日志记录级别:"调试","信息","警告","错误","致命"
"log-level": "",
// 设置每个请求的最大并发下载量,默认 3
"max-concurrent-downloads": 3,
// 设置每次推送的最大同时上传数,默认 5
"max-concurrent-uploads": 5,
// 设置容器网络 MTU
"mtu": 0,
// 设置守护程序的 oom_score_adj,默认 -500
"oom-score-adjust": -500,
// Docker 守护进程的 PID 文件
"pidfile": "",
// 全时间戳机制
"raw-logs": false,
// 设置镜像加速
"registry-mirrors": ["https://192.498.89.232:89"],
// 启用 selinux 支持,默认 false
"selinux-enabled": false,
// 要使用的存储驱动程序
"storage-driver": "",
// 设置默认地址或群集广告地址的接口
"swarm-default-advertise-addr": "",
// 启动 TLS 认证开关,默认 false
"tls": true,
// 通过 CA 认证过的 certificate 文件路径,默认 ~/.docker/ca.pem
"tlscacert": "",
// TLS 的 certificate 文件路径,默认 ~/.docker/cert.pem
"tlscert": "",
// TLS 的 key 文件路径,默认 ~/.docker/key.pem
"tlskey": "",
// 使用 TLS 并做后台进程与客户端通讯的验证,默认 false
"tlsverify": true,
// 使用 userland 代理进行环回流量,默认 true
"userland-proxy": false,
// 用户名称空间的用户/组设置
"userns-remap": "",
// 存储驱动程序选项
"storage-opts": ["overlay2.override_kernel_check=true", "overlay2.size=15G"],
// 容器默认日志驱动程序选项
"log-opts": {
"max-file": "3",
"max-size": "10m"
}
}