一、简介❡
相较于传统的 Linux 发行版来说, 纯容器化系统一般有以下优点:
系统直接内置容器化工具, 例如 Docker、Podman 等
自定义服务大部分可直接通过容器化运行, 简化部署和依赖
系统特定区域具有不可变性, 即无法自行修改和写入, 保证系统完整性
系统会自动滚动更新以保持最新状态
系统一般为精简系统, 资源占用低, 攻击面较小
从上面这些优点来看, 纯容器化系统一般适合运行一些固定服务, 且可以容忍一定的服务中断(系统需要滚动更新). 当然纯容器化系统也有一些缺点:
系统内可能没有内置任何包管理器, 不方便自行扩展系统级组件
某些分区无法写入, 跟现有的一些配置规范等冲突, 需要大量调整
系统默认集成的一些组件可能比较固定且无法替换
需要重新学习配置文件等, 有一定时间成本(yaml 工程师)
二、容器化系统简史❡
最开始做容器化系统的应该是大名鼎鼎的 CoreOS, 当时 CoreOS 开源了很多工具, 比如大名鼎鼎的 etcd 等; 后来 CoreOS 被红帽收购, 原来的版本也停止更新, 新版本 CoreOS 由红帽重构, 此后便出现了两个版本:
Fedora CoreOS(fcos): 红帽收购后重新基于 Fedora 系统创建的 CoreOS
FlatCar: CoreOS 的直接替代品, 现在由 “巨硬” 收购了
从 “名义” 上来说 Fedora CoreOS 算是 CoreOS 的继承者, 但实际上内部已经重构; 所以从 “血统” 上来讲还是 FlatCar 更加像以前的 CoreOS.
三、Fedora CoreOS VS FlatCar❡
Fedora CoreOS 是红帽基于 Fedora 重新创建的 CoreOS, 该系统的特点是使用
rpm-ostree 工具来跟踪系统变化;
rps-ostree 工具有点类似于 Git 一样跟踪系统变化, 同时也允许安装第三方 rpm 包; 相较于 FlatCar 来说其扩展性更强, 且并不是按照分区来保证系统的不可变性, 这样灵活度更高.
与 Fedora CoreOS 不同的是 FlatCar 采用与现在很多安卓手机的类似机制, 采用 A/B 分区的模式进行系统更新, 即系统启动时运行在 A 分区, 更新时只更新 B 分区, 下次重启自动切换到 B 分区启动; 这种方法的好处是简单直接可靠, 坏处就是没有 Fedora CoreOS 那样灵活.
还有一些区别就是 Fedora CoreOS 同时内置了 Podman 和 Docker 工具 , 而 FlatCar 只内置了 Docker; 同时 Fedora CoreOS 网络工具采用的 NetworkManager, 而 FlatCar 采用的是 systemd-networkd.
综合来说两者各有优缺点, 我个人比较不喜欢 NetworkManager, 但 Podman 与 systemd 深度集成这点我还是挺喜欢的; 最后测试完纠结好久还是选择了 FlatCar, 因为 Podman 与 Docker 还是有些差异, 既然用不上又不喜欢 NetworkManager 同时 rpm-ostree 有一定学习成本, 那就干脆 FlatCar 好了; 不过值得说明的是两个系统配置文件大部分通用, 所以只是个人喜好问题.
四、FlatCar 安装❡
FlatCar 官方默认提供了各种软硬件环境的集成安装, 对于纯物理机提供 iso、iPEX 等安装方式, 针对于 VM 部署也提供了预构建的磁盘镜像; 由于安装方式过多, 这里只以 VMWare 平台 VCSA/ESXi 为例, 其他平台请参考
官方文档 .
针对于 VMWare 平台, 需要先下载官方提供的 ova 虚拟机模版文件:
1
curl -LO https://stable.release.flatcar-linux.net/amd64-usr/current/flatcar_production_vmware_ova.ova
SH
4.1、ESXi 部署❡
对于 ESXi 平台可以直接部署, 但每次部署都需要上传 ova 虚拟机模版:
首先新建虚拟机, 并选择 “从 OVA 文件部署”
然后输入虚拟机名称, 并上传 ova 文件
其中启动打开电源选项请根据实际需求调整,
如果稍后要调整磁盘、网卡等则可以先取消勾选, 防止直接启动
其他设置中的 Options 配置暂时可以不写, 下一章节将会详细介绍配置
完成后可调整虚拟机硬件配置(比如磁盘大小、CPU等), 然后启动即可
4.2、VCenter 部署❡
对于 VCenter 来说与 ESXi 大体相同, 不同的是 VCenter 需要新创建一个 “内容库”, 然后上传 ova 虚拟机模版, 安装时需要从内容库来选择 ova, 免去了每次都要上传 ova 的问题.
首先创建存储 ova 的内容库
名称可随意填写
选择本地内容库
然后不启用安全策略, 选择存储即可创建完成
接下来点击 “操作” - “导入项目”
然后选择本地文件导入即可
后续步骤与 ESXi 基本一致, 都是新建虚拟机然后选择 ova 部署, 最后启动就可.
五、FlatCar 配置❡
上面水了一堆, 其实并没有体现出容器化核心配置以及优势; 本部分将着重介绍容器化系统的配置方式和相关的配置样例.
5.1、配置格式❡
由于历史原因容器化系统从最初的 CoreOS 发展到现在 Fedora CoreOS 和 FlatCar 经历了一系列变更, 其中配置文件最初以 Ignition File 变为现在的好几种格式; 下面说一下这几种格式的区别和应该用哪个:
Ignition File: 采用 JSON 格式描述, 是 Fedora CoreOS 和 FlatCar 最终使用的配置文件; 但是大量配置造成了 Ignition File 基本可读性很差, 所以一般都是通过其他配置转换成 Ignition File.
Butane Config: 采用 YAML 格式描述, 比较贴近系统原理, 配置清晰且可读性强; Fedora CoreOS 和 FlatCar 都支持此配置, 一般通过工具将其转换成 Ignition File 再使用.
Container Linux Config: 采用 YAML 格式描述, 该配置格式最初为 CoreOS 创建, 有一定上层抽象且目前似乎只支持 FlatCar, 同样通过工具转换为 Ignition File 使用, 所以不太推荐.
所以综上所述, 对于配置文件只需要看 Butane Config 就行了; 而 Butane Config 我个人认为 Fedora CoreOS 的文档样例描述的相对清晰, 两者都支持 Butane Config 所以区别不大, 所以即使最终选择使用 FlatCar 系统, 在学习配置时也可以参考
Fedora CoreOS 的文档 .
5.2、Butane 安装❡
由于 Butane Config 需要转换成 Ignition File 才能被系统使用, 所以这里会用到一个转换工具, 即
butane
命令; 该命令可执行文件可以直接从
GitHub 下载, 也可以采用 Docker 镜像
quay.io/coreos/butane:release
; 具体的安装方式和细节请参考
官方文档 .
1 2 3 4
docker run --rm -i \ quay.io/coreos/butane:latest \ --pretty --strict < butane_config.yaml \ | base64 -w0
SH
5.3、配置使用❡
详细配置说明放在下面, 这里讲一下怎么简单使用这个配置.
假设有以下 Butane Config, 且文件名为 test.yaml
:
1 2 3 4 5 6 7 8 9 10
variant: flatcar version: 1.0 .0 kernel_arguments: should_not_exist: - flatcar.autologin passwd: users: - name: root ssh_authorized_keys: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMskC9phaoO1WJkQOvXcUxH+DlG8u/2u1ReMXOO9vkbW mritd@linux.com
YAML
我们需要先使用以下命令将其转换为 Ignition 配置:
1
butane --pretty --strict test.yaml | base64 -w0
SH
转换完成后将会输出一长串 base64
编码的文本, 在创建虚拟机时将此内容添加到 Ignition/coreos-cloudinit data
字段中, 同时在 Ignition/coreos-cloudinit data encoding
中指定编码为 base64
, 虚拟机启动后将会自动应用配置.
UHHlUX
5.4、用户配置❡
Butane Config 中可以通过 passwd
属性配置容器化系统的内置用户和用户组, 需要注意的是默认情况下 root 用户是禁止 SSH 登陆的. 简单的配置样例如下:
1 2 3 4 5
passwd: users: - name: root ssh_authorized_keys: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMskC9phaoO1WJkQOvXcUxH+DlG8u/2u1ReMXOO9vkbW mritd@linux.com
YAML
以上配置在系统首次启动时会对 root 用户设置 ssh 登陆密钥, 后续就可以通过 ssh 使用 root 用户登陆; 除了 ssh_authorized_keys
字段以外还有一些常用的配置如下:
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
passwd: # 用户配置 users: - name: test # 设置特定用户的密码, 密码可通过以下命令生成 # openssl passwd -6 -salt SLAT PASSWD password_hash: $6$slat$OKqcnY96krXmy7rRCdpIgN90jMQ5kqJkgJxIc1sEE21SBIyW7kd4hYa91pfCy.lo1qiN4NM7B9R8NTrdGLWq81 ssh_authorized_keys: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMskC9phaoO1WJkQOvXcUxH+DlG8u/2u1ReMXOO9vkbW mritd@linux.com # 定义用户的 UID(一般用于新增用户使用) uid: 1023 # 定义用户的家目录 home_dir: /home/test # 是否自动创建家目录 no_create_home: false # 用户的主用户组 primary_group: test # 用户的其他用户组 groups: - admin # 用户登陆的 shell shell: /bin/bash # 如果对一个已有用户设置为 false, 则启动后会删除此用户 should_exist: true # 设置用户是否为系统级用户 system: true # 组配置 groups: # 用户组名称 - name: test1 # 组 ID gid: 9977 # 组密码 password_hash: ... # 是否应该存在(false 则删除已存在的组) should_exist: true # 是否为系统组 system: false
YAML
5.5、磁盘配置❡
在某些情况下我们可能需要采用独立磁盘作为数据存储, 例如挂载独立的 SSD 磁盘等; 磁盘相关的处理可以通过 storage.disks
字段进行配置, 配置完成后系统首次启动将会按照配置中的定义自动进行磁盘分区. 下面是磁盘配置的详细样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
storage: # 磁盘配置 disks: # 设备文件位置, 推荐直接使用 PCI 位置进行匹配, 因为 /dev/sda 这种配置多磁盘可能会 # 出现磁盘盘符漂移问题 device: /dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:0:0 # 是否强制清除分区表 wipe_table: true # 定义分区结构 partitions: # 定义分区 Label label: data # 分区编号, 如果为 0 则自动选择下一个可用的分区编号 number: 1 # 分区大小, 如果为 0 则默认占据最大空间 size_mib: 0 # 分区开头位置, 同样如果为 0 则采用最大可用的开头位置 start_mib: 0 # 如果分区表已存在是否重置, 为 true 时如果分区表已存在且与配置不符则会自动重建 # 为 false 时如果分区表已存在且不匹配则启动失败 wipe_partition_entry: false # 如果为 true, 当分区表存在且除大小以外都与当前配置相同时, 会自动扩容分区 resize: false
YAML
5.6、文件系统配置❡
上面使用完 storage.disks
对磁盘进行分区后, 还需要通过 storage.filesystems
对磁盘分区进行格式化创建文件系统和挂载; 文件系统创建及挂载的配置样例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
storage: # 文件系统配置 filesystems: # 通过 Label 选中目标分区 label: data # 配置格式化的格式 format: xfs # mkfs 的额外参数 options: - "-f" # 是否在创建之前清除数据 wipe_filesystem: true # 文件系统挂载点 path: /data # 挂载的额外参数 mount_options:
YAML
值得一提的是 FlatCar 默认采用 ext4 作为根文件系统格式, 你可以通过以下配置改变根文件系统格式为 xfs:
1 2 3 4 5
filesystems: - device: /dev/disk/by-partlabel/ROOT wipe_filesystem: true format: xfs label: ROOT
YAML
5.7、文件配置❡
在 FlatCar 和 Fedora CoreOS 这类系统中, 其实大部分配置都是基于文件配置, 通过在 yaml 中定义配置文件内容和属性来达到自动配置的目的. 大部分常用的文件配置参数如下:
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
storage: # 文件配置 files: # 文件的存储路径 - path: /data/testfile # 是否覆盖文件 overwrite: true # 文件权限 mode: 0644 # 文件属主 user: id: 0 name: root # 文件属组 group: id: 0 name: root # 文件内容 contents: # 直接在 yaml 中定义文件内容 inline: | asdsngjsdngda # 与 inline 互斥, 可以通过此字段定义远程文件, 系统启动后会自动下载 # 支持协议 http, https, tftp, s3, gs source: http://exmaple.com/testfile # http 请求头, 当使用远程文件时可设置 http_headers: - name: X-AUTH value: xxxxxxxxx # 与 contents 结构类似, 但是此部分定义的文件内容将会附加到目标文件之后 append: contents: inline: | asnfbshdgbds # 目录配置 # 一般用于创建特定目录使用, 比如 Fedora CoreOS 在使用 Podman 挂载时不会自动 # 创建宿主机目录, 此时可以通过此配置预先创建目录 directories: - path: /data/mysql mode: 0755 user: id: 3306 group: id: 3306 # 链接文件配置 links: # 目标文件位置 - path: /etc/localtime # 原始文件位置 target: ../usr/share/zoneinfo/Asia/Shanghai # 是否创建硬链接 hard: false user: id: 0 group: id: 0
YAML
5.7.1、配置 Hostname❡
以下配置样例用于配置当前主机的 Hostname:
1 2 3 4 5 6
storage: files: - path: /etc/hostname mode: 0644 contents: inline: test
YAML
5.7.2、配置 sysctl❡
以下配置样例用于配置特定的 sysctl 参数
1 2 3 4 5 6 7
storage: files: - path: /etc/sysctl.d/55-custom.conf mode: 0644 contents: inline: | net.core.rmem_max=2500000
YAML
5.7.3、配置静态 IP❡
以下配置样例用于为第一个有线网卡配置静态 IP(默认情况下为 DHCP):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
storage: files: - path: /etc/systemd/network/25-xnet.network contents: inline: | [Match] Name=en* [Network ] DHCP=no NTP=time.windows.com time.apple.com [Address ] Address=172.16.4.24/24 [Route ] Destination=0.0.0.0/0 Gateway=172.16.4.253
YAML
5.7.4、配置 DNS❡
以下配置样例用于配置系统 DNS:
1 2 3 4 5 6 7 8 9 10
storage: files: - path: /etc/systemd/resolved.conf.d/25-xnet.conf contents: inline: | [Resolve] DNS=223.5.5.5 DNS=119.29.29.29 #Domains=~. #DNSStubListener=no
YAML
5.7.5、配置系统更新策略❡
由于 FlatCar 是自动滚动更新的, 滚动更新时需要进行重启保证 A/B 分区切换, 所以为了可控性一般我们需要配置一下可以重启的时间(更新策略):
1 2 3 4 5 6 7 8 9 10
storage: files: - path: /etc/flatcar/update.conf mode: 0420 contents: # 如果有更新的话, 默认在每天 10:30 进行重启更新, 最长的更新窗口期为 1 小时 inline: | REBOOT_STRATEGY=reboot LOCKSMITHD_REBOOT_WINDOW_START=10:30 LOCKSMITHD_REBOOT_WINDOW_LENGTH=1h
YAML
5.7.6、其他配置❡
文件配置是一个灵活的配置选项, 除了做一些系统配置外我们还可以利用它放入一些我们自己的东西, 比如自定义脚本之类的:
1 2 3 4 5 6 7 8 9
storage: files: - path: /opt/scripts/pre-update.sh mode: 0755 contents: inline: | #!/usr/bin/env bash curl -fsSL -XPOST -H 'Authorization: Bearer xxxxxxxxxxxxxxxxxxxxx' https://noti.example.com/message -d 'markdown=false' -d 'message=应用正在更新...'
YAML
5.8、Systemd 配置❡
当需要运行特定服务时, 一般我们需要创建一个 Systemd Service 配置文件, 这时就需要使用 Systemd 配置; Systemd 配置与文件配置类似, 不同之处在于 Systemd 配置虽然也只是定义 Systemd 文件, 但是提供了自启动等针对于 Systemd 的高级配置. 以下为运行 watchtower 容器的样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
systemd: units: - name: watchtower.service enabled: true contents: | [Unit] Description=A container-based solution for automating Docker container base image updates. After=network-online.target Wants=network-online.target [Service ] ExecStartPre=-/usr/bin/docker rm -f watchtower ExecStartPre=/usr/bin/docker pull containrrr/watchtower ExecStart=/usr/bin/docker run --tty \ --name watchtower \ -v /var/run/docker.sock:/var/run/docker.sock \ containrrr/watchtower --cleanup --interval 3600 [Install ] WantedBy=multi-user.target
YAML
需要注意的是, name
属性需要以完整的 systemd units 名称结尾, 即可以通过文件名指定 units 类型, 例如 test.timer
代表创建一个定时器.
5.9、内核参数配置❡
除了一些常规配置以外, 特殊情况下可能需要配置一些内核参数来控制系统行为; 比如默认情况下 FlatCar 会自动登录, 想关闭此行为可以通过一下配置调整内核参数:
1 2 3 4
kernel_arguments: # 确保将特定参数从内核参数中移除 should_not_exist: - flatcar.autologin
YAML
同样也可以使用 should_exist
添加一些内核参数:
1 2 3 4
kernel_arguments: # 确保特定参数被添加到内核参数列表 should_exist: - systemd.unified_cgroup_hierarchy=0
YAML
六、完整样例❡
以下是一个 FlatCar 部署 GitLab 的完整样例, 仅供参考:
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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
variant: flatcar version: 1.0 .0 kernel_arguments: should_not_exist: - flatcar.autologin passwd: users: - name: root # openssl passwd -6 -salt SALT PASSWORD password_hash: $6$kovacs$7svc/7vosETJvIXF3G1SIV9NGdu.j6FRPHPR9DAp0nAQ1CnLuc766hHJQWZlJjlCRj9Nlx4KJjSMGcdtvH4dJ/ ssh_authorized_keys: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMskC9phaoO1WJkQOvXcUxH+DlG8u/2u1ReMXOO9vkbW mritd@linux.com storage: filesystems: - device: /dev/disk/by-partlabel/ROOT wipe_filesystem: true format: xfs label: ROOT # TimeZone links: - path: /etc/localtime target: ../usr/share/zoneinfo/Asia/Shanghai files: # Update policy - path: /etc/flatcar/update.conf mode: 0420 contents: inline: | REBOOT_STRATEGY=reboot LOCKSMITHD_REBOOT_WINDOW_START=10:30 LOCKSMITHD_REBOOT_WINDOW_LENGTH=1h # Sysctl Config - path: /etc/sysctl.d/55-custom.conf mode: 0644 contents: inline: | net.core.rmem_max=2500000 # Set hostname - path: /etc/hostname mode: 0644 contents: inline: gitlab # Set static ip - path: /etc/systemd/network/25-xnet.network contents: inline: | [Match] Name=en* [Network ] DHCP=no NTP=time.windows.com time.apple.com [Address ] Address=172.16.1.6/24 [Route ] Destination=0.0.0.0/0 Gateway=172.16.1.1 # DNS Config - path: /etc/systemd/resolved.conf.d/25-xnet.conf contents: inline: | [Resolve] DNS=223.5.5.5 DNS=119.29.29.29 #Domains=~. #DNSStubListener=no # GitLab Config # ref: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-config-template/gitlab.rb.template - path: /etc/gitlab/gitlab.rb contents: inline: | external_url 'https://git.example.com' gitlab_rails['time_zone'] = 'Asia/Shanghai' ### GitLab email server settings ###! Docs: https://docs.gitlab.com/omnibus/settings/smtp.html ###! **Use smtp instead of sendmail/postfix.** gitlab_rails['smtp_enable'] = true gitlab_rails['smtp_address'] = "smtp.example.com" gitlab_rails['smtp_port'] = 465 gitlab_rails['smtp_user_name'] = "gitlab@example.com" gitlab_rails['smtp_password'] = "asdassgdfgd" gitlab_rails['smtp_domain'] = "example.com" gitlab_rails['smtp_authentication'] = "login" gitlab_rails['smtp_enable_starttls_auto'] = false gitlab_rails['smtp_tls'] = true gitlab_rails['gitlab_email_from'] = 'gitlab@example.com' gitlab_rails['gitlab_email_reply_to'] = 'gitlab@example.com' ### Default Theme ### Available values: ##! `1` for Indigo ##! `2` for Dark ##! `3` for Light ##! `4` for Blue ##! `5` for Green ##! `6` for Light Indigo ##! `7` for Light Blue ##! `8` for Light Green ##! `9` for Red ##! `10` for Light Red gitlab_rails['gitlab_default_theme'] = 2 ### Reply by email ###! Allow users to comment on issues and merge requests by replying to ###! notification emails. ###! Docs: https://docs.gitlab.com/ee/administration/reply_by_email.html gitlab_rails['incoming_email_enabled'] = false ### GitLab Shell settings for GitLab gitlab_rails['gitlab_shell_ssh_port'] = 2222 #### Change the initial default admin password and shared runner registration tokens. ####! **Only applicable on initial setup, changing these settings after database ####! is created and seeded won't yield any change.** gitlab_rails['initial_root_password'] = "hgfghwerwefwfw" gitlab_rails['initial_shared_runners_registration_token'] = "asfdfhfghfgsfsdfs" ### Settings used by GitLab application gitlab_rails['registry_enabled'] = false ### Settings used by Registry application registry['enable'] = false ## GitLab NGINX nginx['listen_port'] = '2080' nginx['listen_https'] = false nginx['redirect_http_to_https'] = false nginx['real_ip_trusted_addresses'] = ['127.0.0.0/8' , '10.0.0.0/8' , '172.16.0.0/12' , '192.168.0.0/16' ] nginx['real_ip_header'] = 'X-Forwarded-For' nginx['real_ip_recursive'] = 'on' ## GitLab Logging logging['logrotate_frequency'] = "daily" # rotate logs daily logging['logrotate_size'] = nil # do not rotate by size by default logging['logrotate_rotate'] = 30 # keep 30 rotated logs logging['logrotate_compress'] = "compress" # see 'man logrotate' logging['logrotate_method'] = "copytruncate" # see 'man logrotate' logging['logrotate_postrotate'] = nil # no postrotate command by default logging['logrotate_dateformat'] = nil # use date extensions for rotated files rather than numbers e.g. a value of "-%Y-%m-%d" would give rotated files like p # Caddy config - path: /etc/caddy/Caddyfile contents: inline: | (LOG_FILE) { log { format transform "[{ts}] {request>remote_ip} [{status}] {request>proto} {request>method} {request>host} {request>uri} {request>headers>User-Agent>[0]}" { time_format "iso8601" } output file "{args.0}" { roll_size 100mb roll_keep 3 roll_keep_for 7d } } } (TLS_MODERN) { protocols tls1.3 } (TLS_INTERMEDIATE) { protocols tls1.2 tls1.3 ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 } (TLS_OLD) { protocols tls1.0 tls1.3 ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_AES_128_GCM_SHA256 TLS_RSA_WITH_AES_256_GCM_SHA384 TLS_RSA_WITH_AES_128_CBC_SHA TLS_RSA_WITH_AES_256_CBC_SHA TLS_RSA_WITH_3DES_EDE_CBC_SHA } (HSTS) { # HSTS (63072000 seconds) header / Strict-Transport-Security "max-age=63072000" } (SECURITY) { # hidden server name header -Server } (ACME_PROVIDER_CLOUDFLARE) { dns cloudflare {$CLOUDFLARE_API_TOKEN } } (ACME_PROVIDER_DNSPOD) { dns dnspod {$DNSPOD_TOKEN } } (ACME_PROVIDER_DUCKDNS) { dns duckdns {$DUCKDNS_API_TOKEN } } (ACME_PROVIDER_GANDI) { dns gandi {$GANDI_API_TOKEN } } (ACME_PROVIDER_ALIYUN) { dns alidns { access_key_id {$ALIYUN_ACCESS_KEY_ID } access_key_secret {$ALIYUN_ACCESS_KEY_SECRET } } } (ACME_DNS) { # 压缩支持 encode zstd gzip # TLS 配置 tls { import TLS_ {args.0 } import ACME_PROVIDER_ {args.1 } resolvers 8.8 .8 .8 } # HSTS import HSTS # security config import SECURITY } # sysctl -w net.core.rmem_max=2500000 # ref https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size { # ZeroSSL acme_ca https://acme.zerossl.com/v2/DV90 #email {$ACME_EMAIL:} #cert_issuer {$ACME_ISSUER:} {$ACME_ISSUER_PARAMS:} # ECC cert key_type p384 servers :443 { protocols h1 h2 h3 } } git.example.com { reverse_proxy gitlab:2080 import ACME_DNS MODERN ALIYUN import LOG_FILE /data/git.example.com.log } - path: /etc/caddy/env contents: inline: | ALIYUN_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxx ALIYUN_ACCESS_KEY_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - path: /etc/mc/config.json contents: inline: | { "version": "10", "aliases": { "nas": { "url": "https://s3.example.com", "accessKey": "admin", "secretKey": "xxxxxxxxxxxxxxxxxxxxxx", "api": "s3v4", "path": "auto" } } } - path: /opt/scripts/gitlab-backup.sh mode: 0755 contents: inline: | #!/usr/bin/env bash set -e TMPDIR=$(mktemp -d) BACKUP_DIR=${TMPDIR}/gitlab BACKUP_DATE=$(date '+%Y-%m-%d-%H-%M-%S' ) BACKUP_FILE=${BACKUP_DATE}_gitlab_backup.tar GITLAB_VERSION=$(docker exec gitlab gitlab-rails runner 'puts Gitlab::VERSION' ) PACKAGE_NAME=gitlab_${GITLAB_VERSION}_${BACKUP_DATE}.tar function cleanup(){ rm -rf ${TMPDIR} } trap cleanup EXIT echo "GitLab Backup Running..." echo "Backup Filename => ${PACKAGE_NAME}" mkdir -p ${BACKUP_DIR} echo "Creating GitLab Backup Tarball..." docker exec -i gitlab gitlab-backup create BACKUP=${BACKUP_DATE} STRATEGY=copy echo "Moving GitLab Tarball..." mv /data/gitlab/data/backups/${BACKUP_FILE} ${BACKUP_DIR} echo "Copying GitLab Config..." docker cp gitlab:/etc/gitlab/gitlab.rb ${BACKUP_DIR} docker cp gitlab:/etc/gitlab/gitlab-secrets.json ${BACKUP_DIR} echo "Packaging All Backup Files..." (cd ${TMPDIR} && tar -cvf ${PACKAGE_NAME} gitlab) echo "Sync Backup File To Remote Storage..." docker run --rm -v /etc/mc:/root/.mc -v /tmp:/host/tmp hub.mi.os.sb/minio/mc cp /host/${TMPDIR}/${PACKAGE_NAME} nas/gitlab/${PACKAGE_NAME} echo "Backup Success!" - path: /opt/scripts/gitlab-restore.sh mode: 0755 contents: inline: | #!/usr/bin/env bash set -e tar -xvf $1 TARBALL=$(basename $(find gitlab/ -type f -name '*.tar' | head -n 1 )) BACKUP_NAME=$(echo ${TARBALL} | sed 's@_gitlab_backup.tar$@@' ) mv gitlab/${TARBALL} /data/gitlab/data/backups chmod 777 /data/gitlab/data/backups/${TARBALL} docker exec -it gitlab gitlab-ctl stop puma docker exec -it gitlab gitlab-ctl stop sidekiq docker exec -it gitlab gitlab-backup restore BACKUP=${BACKUP_NAME} force=yes docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true docker cp gitlab/gitlab.rb gitlab:/etc/gitlab docker cp gitlab/gitlab-secrets.json gitlab:/etc/gitlab systemctl restart gitlab journalctl -fu gitlab systemd: units: - name: gitlab.service enabled: true contents: | [Unit] Description=The DevSecOps Platform After=network-online.target Wants=network-online.target [Service ] TimeoutStartSec=0 ExecStartPre=-/usr/bin/docker pull gitlab/gitlab-ce ExecStart=/usr/bin/docker run --rm --tty \ --name gitlab \ --hostname gitlab \ -p 2222 :22 \ -p 2080 :2080 \ -e GITLAB_OMNIBUS_CONFIG="from_file('/host/etc/gitlab/gitlab.rb')" \ -v /etc/gitlab:/host/etc/gitlab \ -v /opt/scripts:/host/opt/scripts \ -v /data/gitlab/data:/var/opt/gitlab \ -v /data/gitlab/logs:/var/log/gitlab \ -v /data/gitlab/config:/etc/gitlab \ gitlab/gitlab-ce [Install ] WantedBy=multi-user.target - name: gitlab-backup.service enabled: false contents: | [Unit] Description=GitLab Backup Service After=network-online.target gitlab.service Wants=network-online.target [Service ] Type=simple Restart=on-failure ExecStart=/opt/scripts/gitlab-backup.sh [Install ] WantedBy=multi-user.target - name: gitlab-backup.timer enabled: true contents: | [Unit] Description=GitLab Auto Backup Timer After=network-online.target gitlab.service Wants=network-online.target [Timer ] # Run at 3am, 11am, 5pm and 8pm every day in UTC+8 OnCalendar=*-*-* 3 ,11,17,20:00:00 Asia/Shanghai [Install ] WantedBy=timers.target - name: caddy.service enabled: true contents: | [Unit] Description=The Ultimate Server After=network-online.target gitlab.service Wants=network-online.target [Service ] TimeoutStartSec=0 ExecStartPre=-/usr/bin/docker pull mritd/caddy ExecStart=/usr/bin/docker run --rm --tty \ --name caddy \ --env-file /etc/caddy/env \ --link gitlab \ -p 80 :80 \ -p 443 :443/tcp \ -p 443 :443/udp \ -v /etc/caddy:/etc/caddy \ -v /data/caddy/data:/data \ -v /data/caddy/config:/config \ mritd/caddy [Install ] WantedBy=multi-user.target - name: watchtower.service enabled: true contents: | [Unit] Description=A container-based solution for automating Docker container base image updates. After=network-online.target Wants=network-online.target [Service ] ExecStartPre=/usr/bin/docker pull containrrr/watchtower ExecStart=/usr/bin/docker run --rm --tty \ --name watchtower \ -v /var/run/docker.sock:/var/run/docker.sock \ containrrr/watchtower --cleanup --schedule "0 30 17 * * *" [Install ] WantedBy=multi-user.target
YAML
七、其他说明❡
默认情况下 FlatCar 的 /usr
分区是不可写入的, 所以不要尝试向此目录中写入文件这会导致启动失败; 除此之外类似 /opt
之类的目录都可以持久化存放数据; 不过 Fedora CoreOS 似乎并不相同, 具体需要查阅官方文档.
FlatCar 如果想要扩展一些系统级的目录需要使用 Systemd-sysext, 具体请查看
官方文档 ; Fedora CoreOS 可以通过 rpm-ostree 直接安装软件包, 但有些服务可能需要重启才能生效(例如 open-vm-tools).
本篇文章仅描述了基本使用, 复杂情况例如批量更新控制等限于篇幅还请阅读官方文档.