<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Homelab on Code is cheap, let&#39;s talk</title>
    <link>https://blog.ferstar.org/series/homelab/</link>
    <description>Code is cheap, let&#39;s talk</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh-CN</language>
    <copyright>Copyright 2026 ferstar</copyright>
    <lastBuildDate>Sat, 13 Jun 2026 18:40:39 +0800</lastBuildDate>
    <ttl>60</ttl><atom:link href="https://blog.ferstar.org/series/homelab/index.xml" rel="self" type="application/rss+xml" /><image>
      <url>https://blog.ferstar.org/site-logo.png</url>
      <title>Code is cheap, let&#39;s talk</title>
      <link>https://blog.ferstar.org/</link>
    </image>
    
    <item>
      <title>从 OrbStack 换到 Apple Container：顺手把 PostgreSQL 搬了家</title>
      <link>https://blog.ferstar.org/posts/orbstack-to-apple-container-postgres/</link>
      <pubDate>Sat, 13 Jun 2026 18:40:39 +0800</pubDate>
      
      <guid isPermaLink="true">https://blog.ferstar.org/posts/orbstack-to-apple-container-postgres/</guid>
      <description>OrbStack 可以退场了，但 PostgreSQL 数据不能丢；这次用 Apple Container 接管本地数据库，顺手关掉本地 WAL 归档，最后释放了约 19GiB 磁盘空间。</description><content:encoded><![CDATA[<p>今天把本机的 OrbStack 卸了。</p>
<p>不是因为它不好用。恰恰相反，OrbStack 这几年一直是我在 macOS 上最省心的 Docker 替代品。但 Apple 自己的 <code>container</code> CLI 已经能跑 Linux 容器了，本地目前真正长期运行的服务只剩一个 PostgreSQL。既然依赖面已经收窄，就顺手把运行时也收窄一下。</p>
<p>这类迁移最怕一句“直接删了重来”。容器可以重建，数据库不行。</p>

<h3 class="relative group">先看清楚到底在跑什么
    <div id="先看清楚到底在跑什么" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%85%88%e7%9c%8b%e6%b8%85%e6%a5%9a%e5%88%b0%e5%ba%95%e5%9c%a8%e8%b7%91%e4%bb%80%e4%b9%88" aria-label="锚点">#</a>
    </span>
    
</h3>
<p>原来 OrbStack 里只有一个长期运行的容器：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker ps -a --format <span class="s1">'{{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}'</span></span></span></code></pre></div></div>
<p>结果很简单：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">d377e0104620  registry.cheftin.cn/p/postgres17_pd-arm64  scriber_pg  Up 2 weeks (healthy)</span></span></code></pre></div></div>
<p>看 <code>docker inspect</code> 时发现一个坑：<code>docker-compose.yml</code> 里挂的是 <code>./pg17:/var/lib/postgresql/data</code>，但镜像实际用的 <code>PGDATA=/data/data</code>。也就是说，宿主机的 <code>pg17</code> 是空目录，真正的数据在旧容器内部的 <code>/data</code>。</p>
<p>这个差点让迁移变成事故。</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">PGDATA=/data/data
</span></span><span class="line"><span class="cl">/Users/ferstar/myprojects/postgresql/pg17  0B
</span></span><span class="line"><span class="cl">/data                                 7.2G</span></span></code></pre></div></div>
<p>所以不能停掉 OrbStack 后指望“原目录重挂”就完事，必须先从运行中的旧容器导出。</p>

<h3 class="relative group">备份先行
    <div id="备份先行" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%a4%87%e4%bb%bd%e5%85%88%e8%a1%8c" aria-label="锚点">#</a>
    </span>
    
</h3>
<p>我做了两份备份：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> scriber_pg pg_dumpall -U postgres <span class="p">|</span> gzip -9 > pg_dumpall.sql.gz
</span></span><span class="line"><span class="cl">docker <span class="nb">exec</span> scriber_pg tar -C / -cf - data <span class="p">|</span> zstd -T0 -10 > container-data.tar.zst</span></span></code></pre></div></div>
<p>逻辑备份只有 <code>38M</code>，物理归档一开始有 <code>6.8G</code>。当时我还以为数据库很大，后来才发现不是。</p>
<p><code>/data</code> 大头不是业务数据，而是镜像自己的本地 WAL 归档：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">6865.7M  data/backup/wal
</span></span><span class="line"><span class="cl">293.5M   data/data/base
</span></span><span class="line"><span class="cl">126.7M   data/data/log
</span></span><span class="line"><span class="cl">32.0M    data/data/pg_wal</span></span></code></pre></div></div>
<p>真正的表数据也就几百 MB。</p>

<h3 class="relative group">Apple Container 接手
    <div id="apple-container-接手" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#apple-container-%e6%8e%a5%e6%89%8b" aria-label="锚点">#</a>
    </span>
    
</h3>
<p>本机是 macOS 15.7.3，Apple <code>container</code> 官方更偏向 macOS 26，但 Homebrew 已经能装：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew install container
</span></span><span class="line"><span class="cl">container system start</span></span></code></pre></div></div>
<p>第一次启动会安装默认 kernel。跑个 Alpine 测试通过后，把 PostgreSQL 镜像从 Docker 本地导出再导入 Apple Container，绕过私有 registry 凭据问题：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker save registry.cheftin.cn/p/postgres17_pd-arm64:latest -o postgres17_pd-arm64.docker-save.tar
</span></span><span class="line"><span class="cl">container image load -i postgres17_pd-arm64.docker-save.tar</span></span></code></pre></div></div>
<p>正式容器最后这样跑：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">container run -d <span class="se">\
</span></span></span><span class="line"><span class="cl">  --name scriber_pg <span class="se">\
</span></span></span><span class="line"><span class="cl">  --memory 4g <span class="se">\
</span></span></span><span class="line"><span class="cl">  --cpus <span class="m">4</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --shm-size 8g <span class="se">\
</span></span></span><span class="line"><span class="cl">  -p 0.0.0.0:5432:5432 <span class="se">\
</span></span></span><span class="line"><span class="cl">  -v /Users/ferstar/myprojects/postgresql/apple-pg17:/data <span class="se">\
</span></span></span><span class="line"><span class="cl">  -e <span class="nv">DEBUG</span><span class="o">=</span><span class="nb">false</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -e <span class="nv">POSTGRES_PASSWORD</span><span class="o">=</span>... <span class="se">\
</span></span></span><span class="line"><span class="cl">  -e <span class="nv">POSTGRES_HOST_AUTH_METHOD</span><span class="o">=</span>trust <span class="se">\
</span></span></span><span class="line"><span class="cl">  registry.cheftin.cn/p/postgres17_pd-arm64:latest <span class="se">\
</span></span></span><span class="line"><span class="cl">  postgres -c <span class="nv">archive_mode</span><span class="o">=</span>off -c <span class="nv">archive_command</span><span class="o">=</span></span></span></code></pre></div></div>
<p>这里最后两个 <code>-c</code> 很关键。</p>
<p>这个镜像启动时会重写 <code>postgresql.conf</code>，直接改数据目录里的配置会被覆盖。把 <code>archive_mode=off</code> 放到 PostgreSQL 启动参数里，来源会变成 <code>command line</code>，重启后也稳定。</p>
<p>验证结果：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">archive_command=(disabled) source=command line
</span></span><span class="line"><span class="cl">archive_mode=off source=command line
</span></span><span class="line"><span class="cl">wal_level=logical source=configuration file</span></span></code></pre></div></div>
<p><code>wal_level=logical</code> 我没有动。它不是本地备份膨胀的来源，贸然关掉还可能影响逻辑复制或扩展。</p>

<h3 class="relative group">自动启动补一刀
    <div id="自动启动补一刀" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%87%aa%e5%8a%a8%e5%90%af%e5%8a%a8%e8%a1%a5%e4%b8%80%e5%88%80" aria-label="锚点">#</a>
    </span>
    
</h3>
<p>Apple Container 现在还没有 Docker Compose 那种 <code>restart: unless-stopped</code> 体验。<code>brew services start container</code> 只能保证 apiserver 登录后起来，不保证具体容器自动启动。</p>
<p>所以我加了一个用户级 LaunchAgent：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">~/Library/LaunchAgents/com.ferstar.apple-container.scriber-pg.plist</span></span></code></pre></div></div>
<p>实际执行的是一个很小的脚本：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">container system start >/tmp/scriber_pg_container_system_start.log 2><span class="p">&</span><span class="m">1</span> <span class="o">||</span> <span class="nb">true</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> container ls --quiet <span class="p">|</span> grep -Fxq <span class="s1">'scriber_pg'</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">  <span class="nb">exit</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">container start scriber_pg</span></span></code></pre></div></div>
<p>不华丽，但够用。</p>

<h3 class="relative group">清理完的账
    <div id="清理完的账" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%b8%85%e7%90%86%e5%ae%8c%e7%9a%84%e8%b4%a6" aria-label="锚点">#</a>
    </span>
    
</h3>
<p>最后把 OrbStack 卸载并 zap：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">brew uninstall --cask --zap orbstack</span></span></code></pre></div></div>
<p>顺手清掉 <code>~/.orbstack</code>、<code>~/OrbStack</code>、Group Containers 里的残留。因为本机的 Docker CLI 也是 OrbStack 带来的，卸载后 <code>docker</code> 命令也一起没了。这个没关系，现在日常只需要 <code>container</code>。</p>
<p>清理效果：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">迁移中最紧张时可用空间：  6.8GiB
</span></span><span class="line"><span class="cl">删除物理回滚包后：       14GiB
</span></span><span class="line"><span class="cl">卸载 OrbStack 后：       26GiB
</span></span><span class="line"><span class="cl">总体释放：               约 19GiB</span></span></code></pre></div></div>
<p>当前占用：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Apple Container 运行时数据： 3.8G
</span></span><span class="line"><span class="cl">PostgreSQL 新数据目录：     274M
</span></span><span class="line"><span class="cl">迁移逻辑备份和日志：        76M
</span></span><span class="line"><span class="cl">scriber_pg 实际内存：       约 148MiB / 4GiB
</span></span><span class="line"><span class="cl">scriber_pg CPU：            0.00%</span></span></code></pre></div></div>
<p>数据库也还在：</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">postgres|11</span></span></code></pre></div></div>

<h3 class="relative group">小结
    <div id="小结" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%b0%8f%e7%bb%93" aria-label="锚点">#</a>
    </span>
    
</h3>
<p>这次迁移最大的教训不是 Apple Container 怎么用，而是：别相信 compose 文件表面上的 volume，先看运行中容器的真实 <code>PGDATA</code> 和 mount。</p>
<p>另一个收获是，备份目录要分清“数据库运行必需的 WAL”和“额外归档出来的 WAL”。前者不能碰，后者如果本地不需要，就应该关掉。不然一个几百 MB 的数据库，迟早被几 GB 的归档文件吓一跳。</p>
<p>OrbStack 退场，PostgreSQL 留下。机器少跑一个常驻运行时，也算给这台 Mac 减了点负。</p>
]]></content:encoded>
      
    </item>
    
  </channel>
</rss>
