在单机试验环境中,经常需要配置DNS解析、生成SSL证书、保存或者拉取配置脚本,这些操作往往散布到各个节点的实际操作中,较为繁琐且容易出错,所以创建一个虚机镜像来提供统一的服务就是有需求的。以下就是通过在VM上部署实现相关功能的操作实践。

类别 内容
功能 基础架构服务
主机名 infra.contoso.com
IP 192.168.10.254
配置 2core 2G mem 40GB disk
承载服务 DNS以及DNS缓存、时间服务、SSL证书生成和下载、git服务、导航页、Ansible控制台、主机管理

包管理安装

主机准备

基础环境准备

主机环境的准备执行准备:
RockyLinux9的主机部署

# 系统更新
dnf makecache
dnf update -y

# 由于主机模板只给了20G硬盘,所以需要扩容
dnf install cloud-utils-growpart-0.33-1.el9.x86_64
growpart /dev/sda 2
lvextend -l +100%free /dev/rl/root
xfs_growfs /dev/rl/root

# 为后续Gitea修改本地SSH端口为2022端口
echo "127.0.0.1 infra infra.contoso.com" >> /etc/hosts
sed -e 's|#Port 22|Port 2022|g' -i.bak /etc/ssh/sshd_config

# 开启新的防火墙端口
firewall-cmd --permanent --add-port=2022/tcp
firewall-cmd --reload
systemctl restart sshd
systemctl status sshd --no-pager

# 为后续使用创建文件夹
mkdir -p /data/{public,registry}

# 增加github的解析地址
sh -c 'sed -i "/# GitHub520 Host Start/Q" /etc/hosts && curl https://raw.hellogithub.com/hosts >> /etc/hosts'

时间服务器

部署

# 安装时间同步服务器
dnf install -y chrony
systemctl enable --now chronyd
# 设置时区为亚洲/上海
timedatectl set-timezone Asia/Shanghai
# 添加阿里云NTP服务器
cat >> /etc/chronyd.conf <<EOF
pool time.pool.aliyun.com iburst
pool cn.pool.ntp.org iburst

allow 192.168.0.0/16
EOF
# 重启服务
systemctl restart chronyd
systemctl status chronyd --no-pager

# 开启防火墙
firewall-cmd --permanent --add-service=ntp
firewall-cmd --reload

校验

[root@Infra ~]# timedatectl status 
Local time: Tue 2023-10-24 16:58:52 CST
Universal time: Tue 2023-10-24 08:58:52 UTC
RTC time: Tue 2023-10-24 08:58:53
Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no

[root@Infra ~]# chronyc sources
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^? tick.ntp.infomaniak.ch 1 6 3 2 -14ms[ -14ms] +/- 88ms
^? tock.ntp.infomaniak.ch 1 6 1 4 +41ms[ +41ms] +/- 144ms
^? time.neu.edu.cn 1 6 7 1 +209us[ +209us] +/- 9831us
^? ntp6.flashdance.cx 2 6 3 2 -37ms[ -37ms] +/- 143ms

管理面板

为方便管理,我们启用系统自带的cockpit管理界面来对系统进行维护。

部署

dnf install -y cockpit-session-recording cockpit-system
dnf install -y cockpit-navigator cockpit-pcp
dnf install -y cockpit-bridge cockpit-file-sharing
systemctl enable cockpit.socket --now

使用

cockpit

Ansible Cli控制节点

# 安装
dnf install -y ansible

# 创建目录
mkdir -p ~/ansible/{palybook,files,tmp,log}

# 配置文件
cat > ~/ansible/ansible.cfg <<EOF
[defaults]
inventory = ./inventory
remote_tmp = ~/.ansible/tmp
local_tmp = ~/.ansible/tmp
log_path = ~/.ansible/log/ansible.log

forks = 5
poll_interval = 15
transport = smart
host_key_checking = False

[privilege_escalation]
become = True
become_method = sudo
become_user = root
EOF

# 创建主机文件,配置简略
cat > ~/ansible/inventory <<EOF
[Hosts]
infra
[Base]

[K3s]
kmaster[1:2]
node[1:2]

[K8s]
node1
node2
EOF

# 校验
cd ~/ansible/
ansible --version

内外网解析DNS

为了在后续安装部署和Lab环境测试,这里安装部署bind9来作为内部环境的DNS解析服务。同时,后续部署还需要访问外部环境,为了环境隔离和加速DNS的解析服务,一并部署Dnsmasq作为外部环境的解析缓存。使用内部域名时,解析跳转到bind9,非内部域名则跳转阿里云的公共DNS。

Bind部署

# 安装
dnf install -y bind bind-utils
systemctl enable --now named

# 添加解析文件
cat > /var/named/contoso.com.hosts <<EOF
$ttl 3600
$ORIGIN contoso.com.
@ IN SOA Infra. sujx.live.cn. (
2023102502
3600
600
1209600
3600 )
contoso.com. IN NS Infra.
git IN A 192.168.10.254
home IN A 192.168.10.254
pub IN A 192.168.10.254
infra IN A 192.168.10.254

dev IN A 192.168.10.100
EOF

# 添加相关zone配置
cat >> vim /etc/named.rfc1912.zones <<EOF
zone "contoso.com" IN {
type master;
file "contoso.com.hosts";
};
EOF

# 重新加载并校验结果
named-checkconf
named-checkzone "contoso.com" /var/named/contoso.com.hosts
rndc reload
dig git.contoso.com @127.0.0.1

# 配置服务端口为本机10053
sed -e 's|port 53|port 10053|g' -i.bak /etc/named.conf
systemctl restart named
systemctl status --no-pager named

Dnsmasq部署

# 安装
dnf install -y dnsmasq
# 配置转发上游的公共DNS以及contoso.com的解析为本地10053端口
cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
cat > /etc/dnsmasq.conf << EOF
port=53
proxy-dnssec
no-negcache
dns-forward-max=2000
server=223.5.5.5
server=119.29.29.29
server=114.114.114.114
server=/contoso.com/127.0.0.1#10053
log-queries
log-facility=/var/log/dnsmasq/dnsmasq.log
log-async=50
cache-size=100000
EOF

# 创建日志文件
mkdir /var/log/dnsmasq
touch /var/log/dnsmasq/dnsmasq.log

# 设置自动启动
systemctl enable --now dnsmasq
systemctl status dnsmasq --no-pager

# 开启防火墙
firewall-cmd --permanent --add-service=dns
firewall-cmd --reload

# 设置日志轮询
cat > /etc/logrotate.d/dnsmasq << EOF
/var/log/dnsmasq/dnsmasq.log {
notifempty
daily
dateext
rotate 15
sharedscripts
postrotate
[ ! -f /var/run/dnsmasq.pid ] || kill -USR2 `cat /var/run/dnsmasq.pid`
endscript
}
EOF

# 执行测试
logrotate -vf /etc/logrotate.conf

# 设置本地网络地址解析DNS服务器为localhost
nmcli c m ens160 ipv4.dns 127.0.0.1
nmcli c d ens160 && nmcli c u ens160

代码库Gitea

gitea是一个轻量级的Git代码仓库,为是gogs开发停滞之后的分叉,相关使用帮助可参考文档

gitea默认使用3000端口作为web访问端口,22端口为SSH端口。

数据库准备

# 安装
dnf install -y mariadb mariadb-server mariadb-server
# 指定客户端和服务端使用utf8来访问mariadb
cat > /etc/my.cnf.d/charset.cnf <<EOF
[mysqld]
character-set-server = utf8mb4

[client]
default-character-set = utf8mb4
EOF

# 拉起服务
systemctl enable --now mariadb.service
systemctl status --no-pager mariadb.service

# 创建gitea数据库,用户名为gitea,密码为gitea,仅限本地localhost访问
mysql -uroot << EOF
CREATE USER 'gitea' IDENTIFIED BY 'gitea';
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
GRANT ALL PRIVILEGES ON giteadb.* TO 'gitea';
FLUSH PRIVILEGES;
exit
EOF

# 访问测试
mysql -ugitea -pgitea -hlocalhost <<EOF
show databases;
exit
EOF

Gitea的部署

# 下载二进制文件
wget -O gitea https://dl.gitea.com/gitea/1.21/gitea-1.21-linux-amd64
chmod +x gitea
mv gitea /usr/local/bin/gitea
# 创建执行用户
groupadd --system git
adduser \
--system \
--shell /bin/bash \
--comment 'Git Version Control' \
--gid git \
--home-dir /home/git \
--create-home \
git
# 创建工作路径
mkdir -p /data/gitea/{custom,data,log}
chown -R git:git /data/gitea/
chmod -R 750 /data/gitea/
mkdir /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea

# 创建systemd管理文件
cat > /etc/systemd/system/gitea.service <<EOF
[Unit]
Description=Gitea (Git with a cup of tea)
After=network.target
After=mariadb.service

[Service]
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/data/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/data/gitea

[Install]
WantedBy=multi-user.target
EOF

# 拉起服务
systemctl daemon-reload
systemctl enable --now gitea
systemctl status --no-pager gitea

# 临时开启防火墙
firewall-cmd --add-port=3000/tcp
firewall-cmd --reload

页面配置

gitea

容器部署

为了保证操作兼容性,当前仍然使用docker来进行部署。参照以下文档:

RockyLinuxan安装容器服务

证书生成Cert Maker

使用

# 使用苏洋开源的nodejs版本自签证书生成器
docker pull soulteary/certs-maker
# 生成10年期通配符证书,可用于k8s环境部署
docker run --rm -it -e CERT_DNS="contoso.com;*.contoso.com;*.data.contoso.com" -e CERT_C="CN" -e CERT_ST="TJ" -e CERT_L="NK" -e CERT_O="CONTOSO" -e CERT_OU="IT Support" -e FOR_K8S="ON" -e CERT_CN="SUJX LAB" -v /data/public/:/ssl soulteary/certs-maker
# 导入证书
cp /data/files/contoso.com.crt /etc/pki/ca-trust/source/anchors/
update-ca-trust

参考

  1. 文件格式转换
  2. 只有 3MB 的自签名证书制作 Docker 工具镜像:Certs Maker
  3. 如何制作和使用自签名证书

文件下载服务HTTP

部署

为了传递脚本或者证书方便,需要部署一个静态的HTTP文件下载站点。这里使用Nginx容器来实现。

# 创建Dockerfile
mkdir -p ~/Dockerfile/nginx
cat > ~/Dockerfile/nginx/Dockfile <<EOF
FROM nginx:latest
MAINTAINER sujx@live.cn
RUN rm -f /etc/nginx/conf.d/default.conf
COPY ./default.conf /etc/nginx/conf.d/
EOF

# 创建Nginx配置文件
cat > ~/Dockerfile/nginx/default.conf <<EOF
server {
listen 80;
server_name public;
location / {
root /public;
autoindex on;
sub_filter '<h1>Index of /</h1>' '<h1>Get Files</h1>';
sub_filter_once on;
}
}
EOF

# 生成镜像
docker pull nginx
cd ~/Dockerfile/nginx
docker build -f ./Dockfile -t webshare .
# 部署站点
docker run -itd -p 8088:80 --restart always --name publicfile -v /data/files:/public webshare

内部站点导航页

为了可快速方便的查找各种web服务,使用一个站点导航页面来提供书签功能。来源为:个人导航书签

部署站点

# 拉取镜像
docker pull soulteary/flare
# 创建配置目录
mkdir /data/homepage
# 启动容器
docker run -itd -p 5005:5005 -v /data/homepage:/app -e "nologin=0" -e "FLARE_USER=flare" -e "FLARE_PASS=flare" --restart always --name homepage soulteary/flare

配置文件

[root@Infra ~]# tree /data/homepage/
/data/homepage/
├── apps.yml
├── bookmarks.yml
└── config.yml

0 directories, 3 files

# 自定义站点,可以自定义图标、地址、名称和描述文字
[root@Infra ~]# cat /data/homepage/apps.yml
links:
- name: 示例链接
link: https://link.example.com
icon: evernote
desc: 链接描述文本
- name: 示例链接
link: https://link.example.com
icon: FireHydrant
desc: 链接描述文本

# 自定义书签,可以执行分类展示
[root@Infra ~]# cat /data/homepage/bookmarks.yml
categories:
- id: cate-id-0
title: 链接分类1
- id: cate-id-1
title: 链接分类2
- id: cate-id-2
title: 链接分类3
- id: cate-id-3
title: 链接分类4
links:
- name: 示例链接
link: https://link.example.com
icon: checkDecagram
category: cate-id-0
- name: 示例链接
link: https://link.example.com
icon: sofaOutline
category: cate-id-1
- name: 示例链接
link: https://link.example.com
icon: foodCroissant
category: cate-id-2

参考

  1. 源站

收尾

站点发布

由于主机使用多个端口承载多个web服务,所以使用Nginx作为站点前端来实现对后端站点的反向代理。

Nginx的安装

# 部署
dnf install -y nginx
systemctl enable --now nginx
systemctl status --no-pager nginx
firewall-cmd --permanent -add-service={http,https}
firewall-cmd --reload

# 放置证书
mkdir -pv /etc/ssl/contoso.com
cp /data/public/contoso.com.* /etc/ssl/contoso.com/

站点配置

# 配置git.contoso.com
cat > /etc/nginx/conf.d/gitea.conf <<EOF
server {
listen 80 ;
listen [::]:80 ;
return 301 https://$host$request_uri;
server_name git.contoso.com;
}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name git.contoso.com;
charset utf-8;

ssl_certificate "/etc/ssl/contoso.com/contoso.com.crt";
ssl_certificate_key "/etc/ssl/contoso.com/contoso.com.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers PROFILE=SYSTEM;
ssl_prefer_server_ciphers on;

location / {
proxy_pass http://127.0.0.1:3000/;
}
}
EOF
nginx -t

# 配置导航页home.contoso.com
cat > /etc/nginx/conf.d/homepage.conf <<EOF
server {
listen 80 ;
listen [::]:80 ;
return 301 https://$host$request_uri;
server_name home.contoso.com;
}

server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name home.contoso.com;
charset utf-8;

ssl_certificate "/etc/ssl/contoso.com/contoso.com.crt";
ssl_certificate_key "/etc/ssl/contoso.com/contoso.com.key";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers PROFILE=SYSTEM;
ssl_prefer_server_ciphers on;

location / {
proxy_pass http://127.0.0.1:5005/;
}
}
EOF
nginx -t
# 配置公共文件下载,为简化使用,保持使用80端口,并限制访问来源
cat > /etc/nginx/conf.d/public.conf <<EOF
server {
listen 80;
server_name pub.contoso.com;

location / {
autoindex on;
autoindex_exact_size on;
autoindex_localtime on;
root /data/public/;
allow 127.0.0.1;
allow 192.168.10.0/24;
}
}
EOF
nginx -t

# 重新读取配置文件
systemctl reload nginx

清理

# 加固gitea 配置文件权限
chmod 750 /etc/gitea
chmod 640 /etc/gitea/app.ini

# 检查防火墙
firewall-cmd --list-all

# 重启并复查各个站点
systemctl reboot