一、简介 相较于传统的 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
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
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
我们需要先使用以下命令将其转换为 Ignition 配置:
1 butane --pretty --strict test.yaml | base64 -w0
转换完成后将会输出一长串 base64
编码的文本, 在创建虚拟机时将此内容添加到 Ignition/coreos-cloudinit data
字段中, 同时在 Ignition/coreos-cloudinit data encoding
中指定编码为 base64
, 虚拟机启动后将会自动应用配置.
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
以上配置在系统首次启动时会对 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 password_hash: $6$slat$OKqcnY96krXmy7rRCdpIgN90jMQ5kqJkgJxIc1sEE21SBIyW7kd4hYa91pfCy.lo1qiN4NM7B9R8NTrdGLWq81 ssh_authorized_keys: - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMskC9phaoO1WJkQOvXcUxH+DlG8u/2u1ReMXOO9vkbW mritd@linux.com uid: 1023 home_dir: /home/test no_create_home: false primary_group: test groups: - admin shell: /bin/bash should_exist: true system: true groups: - name: test1 gid: 9977 password_hash: ... should_exist: true system: false
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: device: /dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:0:0 wipe_table: true partitions: label: data number: 1 size_mib: 0 start_mib: 0 wipe_partition_entry: false resize: false
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: data format: xfs options: - "-f" wipe_filesystem: true path: /data mount_options:
值得一提的是 FlatCar 默认采用 ext4 作为根文件系统格式, 你可以通过以下配置改变根文件系统格式为 xfs:
1 2 3 4 5 filesystems: - device: /dev/disk/by-partlabel/ROOT wipe_filesystem: true format: xfs label: ROOT
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: inline: | asdsngjsdngda source: http://exmaple.com/testfile http_headers: - name: X-AUTH value: xxxxxxxxx append: contents: inline: | asnfbshdgbds 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
5.7.1、配置 Hostname 以下配置样例用于配置当前主机的 Hostname:
1 2 3 4 5 6 storage: files: - path: /etc/hostname mode: 0644 contents: inline: test
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
5.7.3、配置静态 IP 注意: 静态 IP 配置和 DNS 配置仅适用于 FlatCar, Fedora CoreOS 采用的是 NetworkManager, 所以配置有所不同, 请参考 Host Network Configuration 文档.
以下配置样例用于为第一个有线网卡配置静态 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
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
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: inline: | REBOOT_STRATEGY=reboot LOCKSMITHD_REBOOT_WINDOW_START=10:30 LOCKSMITHD_REBOOT_WINDOW_LENGTH=1h
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=应用正在更新...'
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
需要注意的是, name
属性需要以完整的 systemd units 名称结尾, 即可以通过文件名指定 units 类型, 例如 test.timer
代表创建一个定时器.
5.9、内核参数配置 除了一些常规配置以外, 特殊情况下可能需要配置一些内核参数来控制系统行为; 比如默认情况下 FlatCar 会自动登录, 想关闭此行为可以通过一下配置调整内核参数:
1 2 3 4 kernel_arguments: should_not_exist: - flatcar.autologin
同样也可以使用 should_exist
添加一些内核参数:
1 2 3 4 kernel_arguments: should_exist: - systemd.unified_cgroup_hierarchy=0
六、完整样例 以下是一个 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 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 links: - path: /etc/localtime target: ../usr/share/zoneinfo/Asia/Shanghai files: - path: /etc/flatcar/update.conf mode: 0420 contents: inline: | REBOOT_STRATEGY=reboot LOCKSMITHD_REBOOT_WINDOW_START=10:30 LOCKSMITHD_REBOOT_WINDOW_LENGTH=1h - path: /etc/sysctl.d/55-custom.conf mode: 0644 contents: inline: | net.core.rmem_max=2500000 - path: /etc/hostname mode: 0644 contents: inline: gitlab - 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 - 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 - path: /etc/gitlab/gitlab.rb contents: inline: | external_url 'https://git.example.com' gitlab_rails['time_zone'] = 'Asia/Shanghai' 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' gitlab_rails['gitlab_default_theme'] = 2 gitlab_rails['incoming_email_enabled'] = false gitlab_rails['gitlab_shell_ssh_port'] = 2222 gitlab_rails['initial_root_password'] = "hgfghwerwefwfw" gitlab_rails['initial_shared_runners_registration_token'] = "asfdfhfghfgsfsdfs" gitlab_rails['registry_enabled'] = false registry['enable'] = false 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' logging['logrotate_frequency'] = "daily" logging['logrotate_size'] = nil logging['logrotate_rotate'] = 30 logging['logrotate_compress'] = "compress" logging['logrotate_method'] = "copytruncate" logging['logrotate_postrotate'] = nil logging['logrotate_dateformat'] = nil - 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) { header / Strict-Transport-Security "max-age=63072000" } (SECURITY) { 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 { import TLS_ {args.0 } import ACME_PROVIDER_ {args.1 } resolvers 8.8 .8 .8 } import HSTS import SECURITY } { acme_ca https://acme.zerossl.com/v2/DV90 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 ] 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
七、其他说明 默认情况下 FlatCar 的 /usr
分区是不可写入的, 所以不要尝试向此目录中写入文件这会导致启动失败; 除此之外类似 /opt
之类的目录都可以持久化存放数据; 不过 Fedora CoreOS 似乎并不相同, 具体需要查阅官方文档.
FlatCar 如果想要扩展一些系统级的目录需要使用 Systemd-sysext, 具体请查看 官方文档 ; Fedora CoreOS 可以通过 rpm-ostree 直接安装软件包, 但有些服务可能需要重启才能生效(例如 open-vm-tools).
本篇文章仅描述了基本使用, 复杂情况例如批量更新控制等限于篇幅还请阅读官方文档.