PostgreSQL Docker镜像大版本升级
本机暂存
<p>最近,我发现 <code>PostgreSQL 14</code> 的官方支持在 <code>2026年11月12日</code> 就要结束了, 我正在使用的 <code>postgis/postgis:14-3.2</code> 镜像也即将失去官方支持。为了保持系统的安全性和稳定性,我决定将数据库升级到 <code>PostgreSQL 17</code>。有人说 Docker 镜像没有办法用 <code>pg_upgrade</code> 来升级数据库,但实际上是可以的。今天,我就来记录一下我的升级过程。</p><span id="more"></span><h2 id="一-升级前的准备"><a class="markdownIt-Anchor" href="#一-升级前的准备"></a> 一、升级前的准备</h2><h3 id="1-初始目录结构参考"><a class="markdownIt-Anchor" href="#1-初始目录结构参考"></a> 1. 初始目录结构参考</h3><p>我当前的目录结构如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">├── docker-compose.yml</span><br><span class="line">├── data</span><br><span class="line">│ └── postgres-old-data</span><br></pre></td></tr></table></figure><h3 id="2-备份数据"><a class="markdownIt-Anchor" href="#2-备份数据"></a> 2. 备份数据</h3><p>首先在备份前一定要先停止容器,防止备份时还在写入,造成数据不一致。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker stop postgres-old</span><br></pre></td></tr></table></figure><p>我选择直接备份volume目录,直接打一个tar包。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> data</span><br><span class="line">tar cvf postgres-old.tar postgres-old-data</span><br><span class="line"><span class="built_in">cd</span> ..</span><br></pre></td></tr></table></figure><p>当前目录结构如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">├── docker-compose.yml</span><br><span class="line">├── data</span><br><span class="line">│ ├── postgres-old-data</span><br><span class="line">│ └── postgres-old.tar</span><br></pre></td></tr></table></figure><h3 id="3-拷贝二进制目录"><a class="markdownIt-Anchor" href="#3-拷贝二进制目录"></a> 3. 拷贝二进制目录</h3><p>接下来,我需要拷贝 <code>PostgreSQL 14</code> 的二进制目录,以便在升级过程中使用。我使用的镜像是 <code>postgis/postgis:14-3.2</code>,注意<code>alpine</code>镜像的路径不一样,此处仅做参考。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> data</span><br><span class="line"><span class="built_in">mkdir</span> postgres-old-bin</span><br><span class="line"><span class="built_in">chown</span> 999 postgres-old-bin</span><br><span class="line">docker <span class="built_in">cp</span> postgres-old:/usr/lib/postgresql/14 ./postgres-old-bin/lib</span><br><span class="line">docker <span class="built_in">cp</span> postgres-old:/usr/share/postgresql/14 ./postgres-old-bin/share</span><br><span class="line"><span class="built_in">cd</span> ..</span><br></pre></td></tr></table></figure><p>当前目录结构如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">├── docker-compose.yml</span><br><span class="line">├── data</span><br><span class="line">│ ├── postgres-old-data</span><br><span class="line">│ ├── postgres-old.tar</span><br><span class="line">│ ├── postgres-old-bin</span><br><span class="line">| | ├── lib</span><br><span class="line">| | └── share</span><br></pre></td></tr></table></figure><h3 id="4-初始化新目录"><a class="markdownIt-Anchor" href="#4-初始化新目录"></a> 4. 初始化新目录</h3><p>接下来,我需要初始化一个新的目录来存放升级后的数据。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> data</span><br><span class="line"><span class="built_in">mkdir</span> postgres-new-data</span><br><span class="line"><span class="built_in">chown</span> 999 postgres-new-data</span><br><span class="line"><span class="built_in">cd</span> ..</span><br><span class="line">docker run -it --<span class="built_in">rm</span> --name postgres-new \</span><br><span class="line"> -v ./data/postgres-new-data:/var/lib/postgresql/data \</span><br><span class="line"> -e POSTGRES_PASSWORD=mysecretpassword \</span><br><span class="line"> postgres:17</span><br></pre></td></tr></table></figure><p>数据库创建完成按 <code>Ctrl + C</code> 停止,现在 <code>postgres-new-data</code> 目录已经初始化好了。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">├── docker-compose.yml</span><br><span class="line">├── data</span><br><span class="line">│ └── postgres-old-data</span><br><span class="line">│ └── postgres-old.tar</span><br><span class="line">│ └── postgres-old-bin</span><br><span class="line">│ └── postgres-new-data</span><br></pre></td></tr></table></figure><h2 id="二-执行升级"><a class="markdownIt-Anchor" href="#二-执行升级"></a> 二、执行升级</h2><p>这里要使用需要升级的目标镜像,保证对应的插件在新版本中都包含。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">docker run -it --<span class="built_in">rm</span> --name postgres-upgrade \</span><br><span class="line"> -v ./data/postgres-old-data:/data \</span><br><span class="line"> -v ./data/postgres-new-data:/var/lib/postgresql/data \</span><br><span class="line"> -v ./data/postgres-old-bin/lib:/usr/lib/postgresql/14 \</span><br><span class="line"> -v ./data/postgres-old-bin/share:/usr/share/postgresql/14 \</span><br><span class="line"> --workdir /var/lib/postgresql/data \</span><br><span class="line"> --user postgres \</span><br><span class="line"> -e POSTGRES_PASSWORD=mysecretpassword \</span><br><span class="line"> -e PGUSER=postgres \</span><br><span class="line"> -e PGPASSWORD=mysecretpassword \</span><br><span class="line"> postgis/postgis:17-3.5 \</span><br><span class="line"> pg_upgrade \</span><br><span class="line"> --old-datadir=/data \</span><br><span class="line"> --new-datadir=/var/lib/postgresql/data \</span><br><span class="line"> --old-bindir=/usr/lib/postgresql/14/bin \</span><br><span class="line"> --new-bindir=/usr/lib/postgresql/17/bin</span><br></pre></td></tr></table></figure><p>参数说明:</p><ul><li><code>-v ./data/postgres-old-data:/data</code>:将旧数据目录挂载到容器内的 <code>/data</code>。</li><li><code>-v ./data/postgres-new-data:/var/lib/postgresql/data</code>:将新数据目录挂载到容器内的 PostgreSQL 数据目录。</li><li><code>-v ./data/postgres-old-bin/lib:/usr/lib/postgresql/14</code>:将旧版本的二进制文件挂载到容器内的 <code>/usr/lib/postgresql/14</code>。</li><li><code>-v ./data/postgres-old-bin/share:/usr/share/postgresql/14</code>:将旧版本的共享文件挂载到容器内的 <code>/usr/share/postgresql/14</code>。</li><li><code>--workdir /var/lib/postgresql/data</code>:设置工作目录为新数据目录。</li><li><code>--user postgres</code>:以 postgres 用户身份运行容器。</li><li><code>-e POSTGRES_PASSWORD=mysecretpassword</code>:设置 PostgreSQL 密码环境变量。</li><li><code>-e PGUSER=postgres</code>:设置 PostgreSQL 用户环境变量。</li><li><code>-e PGPASSWORD=mysecretpassword</code>:设置 PostgreSQL 密码环境变量。</li></ul><p>运行完成后,可以根据日志提示进行一些补充工作。</p><ol><li>会生成一个升级插件的sql脚本,可以执行一下,或者后续自行在数据库里执行升级对应的插件版本。</li><li>会生成一个移除旧目录的脚本,鉴于我们后面直接不挂载旧目录了,可以不管。</li><li>还提示推荐执行一下优化查询统计的命令:<code>vacuumdb --all --analyze-in-stages</code>。</li></ol><h2 id="三-升级后的清理工作"><a class="markdownIt-Anchor" href="#三-升级后的清理工作"></a> 三、升级后的清理工作</h2><p>运行新镜像</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mv</span> data/postgres-new-data data/postgres</span><br><span class="line">docker run --name postgres -v ./data/postgres:/var/lib/postgresql/data -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgis/postgis:17-3.5</span><br></pre></td></tr></table></figure><p>执行优化</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">exec</span> -it -u postgres postgres vacuumdb --all --analyze-in-stages</span><br></pre></td></tr></table></figure><p>确认无误后可以删除旧数据了。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">rm</span> postgres-old</span><br><span class="line"><span class="built_in">rm</span> -rf data/postgres-old-data</span><br><span class="line"><span class="built_in">rm</span> -rf data/postgres-old-bin</span><br><span class="line"><span class="built_in">rm</span> -rf data/postgres-old.tar</span><br></pre></td></tr></table></figure>
建议继续学习
- 公司倒了,请让领导先走 (累计阅读 13,341)
- 【2014年版】异地购房提取北京公积金 (累计阅读 9,083)
- 个人开公司的流程,以后用得着 (累计阅读 7,862)
- 一个程序员的血泪史 (累计阅读 6,181)
- 性能测试工具sysbench简介 (累计阅读 5,962)
- 献给有裸辞想法的朋友们 (累计阅读 5,482)
- 也谈PostgreSQL的同步配置(Slony) (累计阅读 5,460)
- 谈谈与数据打交道的工作 (累计阅读 5,300)
- 大公司与风险管理 (累计阅读 5,242)
- 豆瓣是啥? (累计阅读 5,001)