IT技术博客大学习 共学习 共进步

PostgreSQL Docker镜像大版本升级

随遇而安 2026-06-03 09:03:24 累计浏览 2 次
本机暂存
<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>

建议继续学习

  1. 公司倒了,请让领导先走 (累计阅读 13,341)
  2. 【2014年版】异地购房提取北京公积金 (累计阅读 9,083)
  3. 个人开公司的流程,以后用得着 (累计阅读 7,862)
  4. 一个程序员的血泪史 (累计阅读 6,181)
  5. 性能测试工具sysbench简介 (累计阅读 5,962)
  6. 献给有裸辞想法的朋友们 (累计阅读 5,482)
  7. 也谈PostgreSQL的同步配置(Slony) (累计阅读 5,460)
  8. 谈谈与数据打交道的工作 (累计阅读 5,300)
  9. 大公司与风险管理 (累计阅读 5,242)
  10. 豆瓣是啥? (累计阅读 5,001)