<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>文心小屋</title>
  
  <subtitle>来自网络的学习与收集，记录学习点滴</subtitle>
  <link href="https://www.qxz5637.top/atom.xml" rel="self"/>
  
  <link href="https://www.qxz5637.top/"/>
  <updated>2026-02-05T12:33:48.219Z</updated>
  <id>https://www.qxz5637.top/</id>
  
  <author>
    <name>文心</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>MinIO图床上传工具 Docker部署指南</title>
    <link href="https://www.qxz5637.top/2026/02/05/MinIO%E5%9B%BE%E5%BA%8A%E4%B8%8A%E4%BC%A0%E5%B7%A5%E5%85%B7%E6%9C%AC%E5%9C%B0Docker%E9%95%9C%E5%83%8F%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/"/>
    <id>https://www.qxz5637.top/2026/02/05/MinIO%E5%9B%BE%E5%BA%8A%E4%B8%8A%E4%BC%A0%E5%B7%A5%E5%85%B7%E6%9C%AC%E5%9C%B0Docker%E9%95%9C%E5%83%8F%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/</id>
    <published>2026-02-05T12:37:51.488Z</published>
    <updated>2026-02-05T12:33:48.219Z</updated>
    
    <content type="html"><![CDATA[<h1 id="MinIO图床上传工具-Docker部署指南"><a href="#MinIO图床上传工具-Docker部署指南" class="headerlink" title="MinIO图床上传工具 Docker部署指南"></a>MinIO图床上传工具 Docker部署指南</h1><h2 id="镜像信息"><a href="#镜像信息" class="headerlink" title="镜像信息"></a>镜像信息</h2><ul><li><strong>镜像名称</strong>: minio-image-uploader:latest</li><li><strong>镜像文件</strong>: minio-image-uploader.tar</li><li><strong>镜像大小</strong>: 161MB</li><li><strong>基础镜像</strong>: node:18-alpine</li><li><strong>更新时间</strong>: 2026-01-30</li></ul><h2 id="快速部署"><a href="#快速部署" class="headerlink" title="快速部署"></a>快速部署</h2><h3 id="1-加载镜像"><a href="#1-加载镜像" class="headerlink" title="1. 加载镜像"></a>1. 加载镜像</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker load -i minio-image-uploader.tar<br></code></pre></td></tr></tbody></table></figure><h3 id="2-运行容器"><a href="#2-运行容器" class="headerlink" title="2. 运行容器"></a>2. 运行容器</h3><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash">docker run -d \<br>  --name minio-uploader \<br>  -p 3000:3000 \<br>  -e MINIO_ENDPOINT=localhost \<br>  -e MINIO_PORT=9000 \<br>  -e MINIO_ACCESS_KEY=minioadmin \<br>  -e MINIO_SECRET_KEY=minioadmin \<br>  -e MINIO_BUCKET=images \<br>  -e CUSTOM_DOMAIN=http://localhost:9000 \<br>  -e UPLOAD_PREFIX=images/ \<br>  minio-image-uploader:latest<br></code></pre></td></tr></tbody></table></figure><h3 id="3-访问应用"><a href="#3-访问应用" class="headerlink" title="3. 访问应用"></a>3. 访问应用</h3><p>打开浏览器访问: <a href="http://localhost:3000/">http://localhost:3000</a></p><h2 id="环境变量配置"><a href="#环境变量配置" class="headerlink" title="环境变量配置"></a>环境变量配置</h2><table><thead><tr><th>变量名</th><th>描述</th><th>默认值</th><th>示例</th></tr></thead><tbody><tr><td>MINIO_ENDPOINT</td><td>MinIO服务地址</td><td>localhost</td><td>192.168.1.100</td></tr><tr><td>MINIO_PORT</td><td>MinIO服务端口</td><td>9000</td><td>9000</td></tr><tr><td>MINIO_ACCESS_KEY</td><td>MinIO访问密钥</td><td>minioadmin</td><td>your-access-key</td></tr><tr><td>MINIO_SECRET_KEY</td><td>MinIO秘密密钥</td><td>minioadmin</td><td>your-secret-key</td></tr><tr><td>MINIO_BUCKET</td><td>存储桶名称</td><td>images</td><td>my-images</td></tr><tr><td>MINIO_USE_SSL</td><td>是否使用SSL</td><td>false</td><td>true</td></tr><tr><td>CUSTOM_DOMAIN</td><td>自定义域名</td><td><a href="http://localhost:9000/">http://localhost:9000</a></td><td><a href="https://cdn.example.com/">https://cdn.example.com</a></td></tr><tr><td>FILE_NAME_TEMPLATE</td><td>文件命名模板</td><td>{timestamp}.{extName}</td><td>{year}/{month}/{day}/{md5}.{extName}</td></tr><tr><td>UPLOAD_PREFIX</td><td>默认目录前缀</td><td>无</td><td>images/ 或 gallery/2026/</td></tr><tr><td>PORT</td><td>应用端口</td><td>3000</td><td>3000</td></tr></tbody></table><h2 id="功能特性"><a href="#功能特性" class="headerlink" title="功能特性"></a>功能特性</h2><p>✅ <strong>图片上传</strong></p><ul><li>支持拖拽上传</li><li>支持多文件同时上传</li><li>支持 JPEG, PNG, GIF, WebP 格式</li><li>最大文件大小：10MB</li></ul><p>✅ <strong>文件管理</strong></p><ul><li>灵活的文件命名规则（时间戳、MD5、日期结构等）</li><li>支持自定义目录前缀</li><li>智能重复文件处理（自动重命名、跳过、覆盖）</li><li>环境变量默认配置</li></ul><p>✅ <strong>系统设置</strong></p><ul><li>动态MinIO连接配置（支持运行时修改）</li><li><strong>配置持久化</strong>（重启容器后设置不丢失）</li><li>连接测试功能</li><li>设置导入/导出</li></ul><p>✅ <strong>Web界面</strong></p><ul><li>响应式设计</li><li>实时上传进度显示</li><li>图片预览和管理</li><li>系统信息监控</li></ul><h2 id="新版本改进"><a href="#新版本改进" class="headerlink" title="新版本改进"></a>新版本改进</h2><h3 id="🎉-配置持久化功能"><a href="#🎉-配置持久化功能" class="headerlink" title="🎉 配置持久化功能"></a>🎉 配置持久化功能</h3><ul><li><strong>问题</strong>：之前版本在容器重启后会丢失系统设置</li><li><strong>解决</strong>：新版本使用 <code>config.json</code> 文件保存动态配置</li><li><strong>效果</strong>：通过Web界面修改的MinIO连接参数会永久保存</li></ul><h3 id="🎯-环境变量增强"><a href="#🎯-环境变量增强" class="headerlink" title="🎯 环境变量增强"></a>🎯 环境变量增强</h3><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><span class="hljs-comment"># 新增：默认目录前缀支持</span><br>-e UPLOAD_PREFIX=images/<br>-e UPLOAD_PREFIX=gallery/$(<span class="hljs-built_in">date</span> +%Y)/<br><br><span class="hljs-comment"># 优化：文件命名模板</span><br>-e FILE_NAME_TEMPLATE={timestamp}.{extName}<br>-e FILE_NAME_TEMPLATE={year}/{month}/{day}/{md5}.{extName}<br></code></pre></td></tr></tbody></table></figure><h3 id="📦-镜像优化"><a href="#📦-镜像优化" class="headerlink" title="📦 镜像优化"></a>📦 镜像优化</h3><ul><li>✅ 移除了开发文件（.claude/、<em>.md、test-</em>）</li><li>✅ 优化了文件结构和构建过程</li><li>✅ 更小的镜像体积和更快的启动速度</li></ul><h2 id="使用-Docker-Compose"><a href="#使用-Docker-Compose" class="headerlink" title="使用 Docker Compose"></a>使用 Docker Compose</h2><p>创建 <code>docker-compose.yml</code>:</p><figure class="highlight yaml"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">'3.8'</span><br><span class="hljs-attr">services:</span><br>  <span class="hljs-attr">minio-uploader:</span><br>    <span class="hljs-attr">image:</span> <span class="hljs-string">minio-image-uploader:latest</span><br>    <span class="hljs-attr">container_name:</span> <span class="hljs-string">minio-uploader</span><br>    <span class="hljs-attr">ports:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">"3000:3000"</span><br>    <span class="hljs-attr">environment:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">MINIO_ENDPOINT=minio</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">MINIO_PORT=9000</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">MINIO_ACCESS_KEY=minioadmin</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">MINIO_SECRET_KEY=minioadmin</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">MINIO_BUCKET=images</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">MINIO_USE_SSL=false</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">CUSTOM_DOMAIN=http://localhost:9000</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">FILE_NAME_TEMPLATE={timestamp}.{extName}</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">UPLOAD_PREFIX=uploads/</span><br>    <span class="hljs-attr">volumes:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">./config:/app/config.json</span>  <span class="hljs-comment"># 可选：持久化配置文件</span><br>    <span class="hljs-attr">depends_on:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">minio</span><br>    <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span><br><br>  <span class="hljs-attr">minio:</span><br>    <span class="hljs-attr">image:</span> <span class="hljs-string">quay.io/minio/minio:latest</span><br>    <span class="hljs-attr">container_name:</span> <span class="hljs-string">minio</span><br>    <span class="hljs-attr">ports:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">"9000:9000"</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">"9001:9001"</span><br>    <span class="hljs-attr">environment:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">MINIO_ROOT_USER=minioadmin</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">MINIO_ROOT_PASSWORD=minioadmin</span><br>    <span class="hljs-attr">command:</span> <span class="hljs-string">server</span> <span class="hljs-string">/data</span> <span class="hljs-string">--console-address</span> <span class="hljs-string">":9001"</span><br>    <span class="hljs-attr">volumes:</span><br>      <span class="hljs-bullet">-</span> <span class="hljs-string">minio_data:/data</span><br>    <span class="hljs-attr">restart:</span> <span class="hljs-string">unless-stopped</span><br><br><span class="hljs-attr">volumes:</span><br>  <span class="hljs-attr">minio_data:</span><br></code></pre></td></tr></tbody></table></figure><p>启动：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker-compose up -d<br></code></pre></td></tr></tbody></table></figure><h2 id="配置持久化"><a href="#配置持久化" class="headerlink" title="配置持久化"></a>配置持久化</h2><h3 id="方案1：使用内置配置文件（推荐）"><a href="#方案1：使用内置配置文件（推荐）" class="headerlink" title="方案1：使用内置配置文件（推荐）"></a>方案1：使用内置配置文件（推荐）</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 正常启动，配置会自动保存到容器内的config.json</span><br>docker run -d --name minio-uploader -p 3000:3000 minio-image-uploader:latest<br></code></pre></td></tr></tbody></table></figure><h3 id="方案2：挂载配置文件"><a href="#方案2：挂载配置文件" class="headerlink" title="方案2：挂载配置文件"></a>方案2：挂载配置文件</h3><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><span class="hljs-comment"># 将配置文件挂载到主机，实现跨容器持久化</span><br>docker run -d \<br>  --name minio-uploader \<br>  -p 3000:3000 \<br>  -v ./app-config.json:/app/config.json \<br>  minio-image-uploader:latest<br></code></pre></td></tr></tbody></table></figure><h2 id="健康检查"><a href="#健康检查" class="headerlink" title="健康检查"></a>健康检查</h2><p>容器提供健康检查端点：</p><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 检查容器状态</span><br>docker ps<br><br><span class="hljs-comment"># 查看应用日志</span><br>docker logs minio-uploader<br><br><span class="hljs-comment"># 测试应用健康状态</span><br>curl http://localhost:3000/health<br><br><span class="hljs-comment"># 查看系统配置</span><br>curl http://localhost:3000/api/config<br></code></pre></td></tr></tbody></table></figure><h2 id="数据流和存储"><a href="#数据流和存储" class="headerlink" title="数据流和存储"></a>数据流和存储</h2><figure class="highlight mipsasm"><table><tbody><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><code class="hljs mipsasm">用户上传 → Docker容器(minio-uploader) → MinIO服务器 → 文件存储<br>                    ↓<br>               <span class="hljs-built_in">config</span>.<span class="hljs-keyword">json </span>(配置持久化)<br></code></pre></td></tr></tbody></table></figure><ul><li><strong>文件存储</strong>：直接存储在MinIO对象存储服务器</li><li><strong>配置存储</strong>：保存在容器内的config.json文件</li><li><strong>应用本身</strong>：无状态，可以随时重启</li></ul><h2 id="API端点"><a href="#API端点" class="headerlink" title="API端点"></a>API端点</h2><table><thead><tr><th>端点</th><th>方法</th><th>描述</th></tr></thead><tbody><tr><td><code>/api/upload/direct</code></td><td>POST</td><td>单文件上传</td></tr><tr><td><code>/api/upload/multiple</code></td><td>POST</td><td>批量上传</td></tr><tr><td><code>/api/upload/picgo</code></td><td>POST</td><td>PicGo兼容接口</td></tr><tr><td><code>/api/images</code></td><td>GET</td><td>图片列表</td></tr><tr><td><code>/api/config</code></td><td>GET</td><td>系统配置</td></tr><tr><td><code>/api/update-minio-config</code></td><td>POST</td><td>更新MinIO配置</td></tr><tr><td><code>/api/test-minio</code></td><td>POST</td><td>测试MinIO连接</td></tr><tr><td><code>/health</code></td><td>GET</td><td>健康检查</td></tr></tbody></table><h2 id="故障排除"><a href="#故障排除" class="headerlink" title="故障排除"></a>故障排除</h2><h3 id="1-连接失败"><a href="#1-连接失败" class="headerlink" title="1. 连接失败"></a>1. 连接失败</h3><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><span class="hljs-comment"># 检查MinIO服务状态</span><br>docker logs minio<br><br><span class="hljs-comment"># 检查网络连通性</span><br>docker <span class="hljs-built_in">exec</span> minio-uploader ping minio<br><br><span class="hljs-comment"># 验证端口映射</span><br>netstat -tulpn | grep :3000<br></code></pre></td></tr></tbody></table></figure><h3 id="2-配置丢失"><a href="#2-配置丢失" class="headerlink" title="2. 配置丢失"></a>2. 配置丢失</h3><ul><li>✅ <strong>已修复</strong>：新版本支持配置持久化</li><li>如果仍有问题，检查容器写入权限</li><li>可选择挂载配置文件到主机目录</li></ul><h3 id="3-上传失败"><a href="#3-上传失败" class="headerlink" title="3. 上传失败"></a>3. 上传失败</h3><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><span class="hljs-comment"># 查看详细日志</span><br>docker logs -f minio-uploader<br><br><span class="hljs-comment"># 检查存储桶权限</span><br>docker <span class="hljs-built_in">exec</span> minio mc admin info <span class="hljs-built_in">local</span><br><br><span class="hljs-comment"># 测试文件上传</span><br>curl -X POST -F <span class="hljs-string">"image=@test.jpg"</span> http://localhost:3000/api/upload/direct<br></code></pre></td></tr></tbody></table></figure><h3 id="4-性能优化"><a href="#4-性能优化" class="headerlink" title="4. 性能优化"></a>4. 性能优化</h3><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 内存限制（可选）</span><br>docker run -m 512m minio-image-uploader:latest<br><br><span class="hljs-comment"># CPU限制（可选）  </span><br>docker run --cpus=<span class="hljs-string">"0.5"</span> minio-image-uploader:latest<br></code></pre></td></tr></tbody></table></figure><h2 id="高级用法"><a href="#高级用法" class="headerlink" title="高级用法"></a>高级用法</h2><h3 id="1-生产环境部署"><a href="#1-生产环境部署" class="headerlink" title="1. 生产环境部署"></a>1. 生产环境部署</h3><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash">docker run -d \<br>  --name minio-uploader-prod \<br>  --restart=always \<br>  -p 80:3000 \<br>  -e NODE_ENV=production \<br>  -e MINIO_ENDPOINT=minio.example.com \<br>  -e MINIO_USE_SSL=<span class="hljs-literal">true</span> \<br>  -e CUSTOM_DOMAIN=https://cdn.example.com \<br>  -v /var/log/minio-uploader:/app/logs \<br>  minio-image-uploader:latest<br></code></pre></td></tr></tbody></table></figure><h3 id="2-负载均衡"><a href="#2-负载均衡" class="headerlink" title="2. 负载均衡"></a>2. 负载均衡</h3><figure class="highlight yaml"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs yaml"><span class="hljs-comment"># docker-compose.yml</span><br><span class="hljs-attr">services:</span><br>  <span class="hljs-attr">minio-uploader-1:</span><br>    <span class="hljs-attr">image:</span> <span class="hljs-string">minio-image-uploader:latest</span><br>    <span class="hljs-attr">ports:</span> [<span class="hljs-string">"3001:3000"</span>]<br>  <br>  <span class="hljs-attr">minio-uploader-2:</span><br>    <span class="hljs-attr">image:</span> <span class="hljs-string">minio-image-uploader:latest</span>  <br>    <span class="hljs-attr">ports:</span> [<span class="hljs-string">"3002:3000"</span>]<br>  <br>  <span class="hljs-attr">nginx:</span><br>    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:alpine</span><br>    <span class="hljs-attr">ports:</span> [<span class="hljs-string">"80:80"</span>]<br>    <span class="hljs-comment"># 配置负载均衡到3001和3002端口</span><br></code></pre></td></tr></tbody></table></figure><h2 id="安全建议"><a href="#安全建议" class="headerlink" title="安全建议"></a>安全建议</h2><ol><li><p><strong>访问控制</strong></p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 使用防火墙限制访问</span><br>ufw allow from 192.168.1.0/24 to any port 3000<br></code></pre></td></tr></tbody></table></figure></li><li><p><strong>密钥管理</strong></p><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><span class="hljs-comment"># 使用环境变量文件</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"MINIO_ACCESS_KEY=your-secure-key"</span> &gt; .<span class="hljs-built_in">env</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"MINIO_SECRET_KEY=your-secure-secret"</span> &gt;&gt; .<span class="hljs-built_in">env</span><br>docker run --env-file .<span class="hljs-built_in">env</span> minio-image-uploader:latest<br></code></pre></td></tr></tbody></table></figure></li><li><p><strong>HTTPS部署</strong></p><ul><li>使用反向代理（Nginx/Traefik）</li><li>配置SSL证书</li><li>强制HTTPS重定向</li></ul></li></ol><h2 id="版本更新"><a href="#版本更新" class="headerlink" title="版本更新"></a>版本更新</h2><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 备份当前配置</span><br>docker <span class="hljs-built_in">cp</span> minio-uploader:/app/config.json ./config-backup.json<br><br><span class="hljs-comment"># 停止旧容器</span><br>docker stop minio-uploader<br><br><span class="hljs-comment"># 加载新镜像</span><br>docker load -i minio-image-uploader-new.tar<br><br><span class="hljs-comment"># 启动新容器（配置会自动迁移）</span><br>docker run -d --name minio-uploader-new \<br>  -v ./config-backup.json:/app/config.json \<br>  minio-image-uploader:latest<br></code></pre></td></tr></tbody></table></figure><h2 id="支持"><a href="#支持" class="headerlink" title="支持"></a>支持</h2><ul><li><strong>文档</strong>：查看项目README和源代码</li><li><strong>日志</strong>：<code>docker logs -f minio-uploader</code></li><li><strong>配置</strong>：访问 <a href="http://localhost:3000/">http://localhost:3000</a> → 系统设置</li><li><strong>API测试</strong>：使用curl或Postman测试各个端点</li></ul><p>如有问题，请查看容器日志或提交Issue。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;MinIO图床上传工具-Docker部署指南&quot;&gt;&lt;a href=&quot;#MinIO图床上传工具-Docker部署指南&quot; class=&quot;headerlink&quot; title=&quot;MinIO图床上传工具 Docker部署指南&quot;&gt;&lt;/a&gt;MinIO图床上传工具 Docker部署</summary>
      
    
    
    
    <category term="学习" scheme="https://www.qxz5637.top/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
    <category term="网络" scheme="https://www.qxz5637.top/tags/%E7%BD%91%E7%BB%9C/"/>
    
  </entry>
  
  <entry>
    <title>Typora Plugin README（中文）</title>
    <link href="https://www.qxz5637.top/2026/01/27/Typora%20Plugin%20README%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89.md/"/>
    <id>https://www.qxz5637.top/2026/01/27/Typora%20Plugin%20README%EF%BC%88%E4%B8%AD%E6%96%87%EF%BC%89.md/</id>
    <published>2026-01-27T15:06:37.594Z</published>
    <updated>2026-02-03T04:37:53.769Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Typora-Plugin-README（中文）"><a href="#Typora-Plugin-README（中文）" class="headerlink" title="Typora Plugin README（中文）"></a>Typora Plugin README（中文）</h1><div align="center"><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/typora_plugin.png" alt="typora_plugin" width="400">    <div align="center">        <a href="https://github.com/obgnail/typora_plugin/releases/latest"><img src="https://img.shields.io/github/v/release/obgnail/typora_plugin"></a><a href="https://github.com/obgnail/typora_plugin/stargazers"><img src="https://img.shields.io/github/stars/obgnail/typora_plugin?style=flat"></a><a href="https://github.com/obgnail/typora_plugin/issues"><img src="https://img.shields.io/github/issues-closed/obgnail/typora_plugin.svg"></a><a href="https://github.com/obgnail/typora_plugin/tree/master/plugin"><img src="https://img.shields.io/badge/implementation-native-greenbule"></a><a href="https://github.com/obgnail/typora_plugin?tab=readme-ov-file#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95%E4%B8%80%E8%87%AA%E5%8A%A8"><img src="https://img.shields.io/badge/platform-Windows%20%7C%20Linux-0085a1"></a><a href="https://github.com/obgnail/typora_plugin/blob/master/LICENSE"><img src="https://img.shields.io/github/license/obgnail/typora_plugin"></a><a href="https://deepwiki.com/obgnail/typora_plugin"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>    </div></div><table><thead><tr><th>#</th><th>插件</th><th>功能</th><th>默认启用</th></tr></thead><tbody><tr><td>1</td><td>window_tab</td><td>标签页管理</td><td></td></tr><tr><td>2</td><td>search_multi</td><td>多元文件搜索</td><td></td></tr><tr><td>3</td><td>collapse_paragraph</td><td>章节折叠</td><td>×</td></tr><tr><td>4</td><td>collapse_list</td><td>列表折叠</td><td>×</td></tr><tr><td>5</td><td>collapse_table</td><td>表格折叠</td><td>×</td></tr><tr><td>6</td><td>md_padding</td><td>中英文混排优化</td><td></td></tr><tr><td>7</td><td>slash_commands</td><td>斜杠命令</td><td></td></tr><tr><td>8</td><td>templater</td><td>文件模板</td><td></td></tr><tr><td>9</td><td>resource_manager</td><td>一键清除无用图片</td><td></td></tr><tr><td>10</td><td>fence_enhance</td><td>复制、折叠、格式化代码</td><td></td></tr><tr><td>11</td><td>toc</td><td>在右侧生成大纲目录</td><td></td></tr><tr><td>12</td><td>commander</td><td>命令行环境</td><td></td></tr><tr><td>13</td><td>toolbar</td><td>多功能搜索</td><td></td></tr><tr><td>14</td><td>right_click_menu</td><td>右键菜单统一管理插件</td><td></td></tr><tr><td>15</td><td>pie_menu</td><td>圆盘菜单</td><td>×</td></tr><tr><td>16</td><td>datatables</td><td>表格增强（搜索、过滤、分页、排序等）</td><td>×</td></tr><tr><td>17</td><td>preferences</td><td>插件配置</td><td></td></tr><tr><td>18</td><td>markmap</td><td>提供 markmap 组件支持</td><td></td></tr><tr><td>19</td><td>echarts</td><td>提供 echarts 组件支持</td><td></td></tr><tr><td>20</td><td>chart</td><td>提供 chartjs 组件支持</td><td></td></tr><tr><td>21</td><td>drawIO</td><td>提供 drawIO 组件支持</td><td></td></tr><tr><td>22</td><td>abc</td><td>提供 abcjs 组件支持</td><td></td></tr><tr><td>23</td><td>calendar</td><td>提供 tui.calendar 组件支持</td><td></td></tr><tr><td>24</td><td>wavedrom</td><td>提供 wavedrom 组件支持</td><td></td></tr><tr><td>25</td><td>marp</td><td>提供 marp 组件支持</td><td></td></tr><tr><td>26</td><td>plantUML</td><td>提供 PlantUML 组件支持</td><td>×</td></tr><tr><td>27</td><td>callouts</td><td>提供 callouts 支持</td><td></td></tr><tr><td>28</td><td>text_stylize</td><td>文字风格化</td><td></td></tr><tr><td>29</td><td>read_only</td><td>只读模式</td><td></td></tr><tr><td>30</td><td>blur</td><td>模糊模式</td><td></td></tr><tr><td>31</td><td>kanban</td><td>看板</td><td></td></tr><tr><td>32</td><td>timeline</td><td>时间线</td><td></td></tr><tr><td>33</td><td>chat</td><td>聊天</td><td></td></tr><tr><td>34</td><td>file_counter</td><td>显示目录下的文件数</td><td></td></tr><tr><td>35</td><td>auto_number</td><td>章节、表格、图片、代码块等自动编号</td><td></td></tr><tr><td>36</td><td>imageReviewer</td><td>图片查看器</td><td></td></tr><tr><td>37</td><td>chineseSymbolAutoPairer</td><td>中文符号自动补全</td><td></td></tr><tr><td>38</td><td>resize_table</td><td>调整表格行高列宽</td><td></td></tr><tr><td>39</td><td>resize_image</td><td>调整图片显示大小</td><td></td></tr><tr><td>40</td><td>export_enhance</td><td>导出 HTML 时避免图片丢失</td><td></td></tr><tr><td>41</td><td>sidebar_enhance</td><td>显示其他扩展名文件、记忆折叠状态、拖拽排序</td><td></td></tr><tr><td>42</td><td>markdownLint</td><td>markdown 格式检查</td><td></td></tr><tr><td>43</td><td>go_top</td><td>一键到文章顶部、底部</td><td></td></tr><tr><td>44</td><td>truncate_text</td><td>暂时隐藏内容，提高大文件渲染性能</td><td>×</td></tr><tr><td>45</td><td>dark</td><td>夜间模式</td><td></td></tr><tr><td>46</td><td>no_image</td><td>无图模式</td><td></td></tr><tr><td>47</td><td>myopic_defocus</td><td>离焦视力舒缓</td><td></td></tr><tr><td>48</td><td>updater</td><td>一键升级插件</td><td></td></tr><tr><td>49</td><td>easy_modify</td><td>编辑工具</td><td></td></tr><tr><td>50</td><td>editor_width_slider</td><td>写作区宽度调整</td><td></td></tr><tr><td>51</td><td>redirectLocalRootUrl</td><td>重定向本地资源根目录</td><td>×</td></tr><tr><td>52</td><td>scrollBookmarker</td><td>书签管理器</td><td>×</td></tr><tr><td>53</td><td>cipher</td><td>加密文件</td><td>×</td></tr><tr><td>54</td><td>ripgrep</td><td>使用 ripgrep 搜索文件</td><td>×</td></tr><tr><td>55</td><td>article_uploader</td><td>一键上传博客到支持的所有平台</td><td>×</td></tr><tr><td>56</td><td>cursor_history</td><td>光标跳转</td><td>×</td></tr><tr><td>57</td><td>static_markers</td><td>Markdown 标记常显</td><td>×</td></tr><tr><td>58</td><td>custom</td><td>开放平台，用户自定义插件（高级）</td><td></td></tr><tr><td>59</td><td>hotkeys</td><td>快捷键注册中心（高级）</td><td></td></tr><tr><td>60</td><td>quickButton</td><td>于右下角添加功能按钮（高级）</td><td></td></tr><tr><td>61</td><td>json_rpc</td><td>外部操纵 Typora（高级）</td><td>×</td></tr></tbody></table><blockquote><p>如果有需求或发现 BUG，欢迎 <a href="https://github.com/obgnail/typora_plugin/issues/new">提 issue</a>，欢迎 PR。如果觉得本项目对您有帮助，请不吝点亮一个 Star ⭐！</p></blockquote><h2 id="Q-A"><a href="#Q-A" class="headerlink" title="Q&amp;A"></a>Q&amp;A</h2><ul><li><strong>我的 Typora 能用吗？</strong> 要求 Typora 版本大于等于 0.9.98（最后一个免费版本）。</li><li><strong>如何修改插件配置？</strong> 通过右键菜单 -&gt; 少用插件 -&gt; 插件配置。<strong>尊重用户的一切选择</strong>，所有的插件和功能皆可永久启用 / 禁用。</li><li><strong>如何升级插件？</strong> 通过右键菜单 -&gt; 少用插件 -&gt; 插件配置 -&gt; 升级插件。</li><li><strong>如何卸载插件？</strong> 通过右键菜单 -&gt; 少用插件 -&gt; 插件配置 -&gt; 卸载插件。</li><li><strong>如何编写插件？</strong> 本项目坚持 <strong>No BuildTime</strong>，因此无需安装任何开发环境，详情请参考 <a href="https://github.com/obgnail/typora_plugin/blob/master/plugin/custom/README.md">Readme</a>。</li><li><strong>支持 Typora for Mac 吗？</strong> 我没有 Mac 设备，故暂不支持。</li><li><strong>还有其他问题？</strong> 欢迎前往 <a href="https://deepwiki.com/obgnail/typora_plugin">AI Wiki</a> 提问或查阅社区讨论。</li></ul><h2 id="如何使用：Windows-Linux-平台"><a href="#如何使用：Windows-Linux-平台" class="headerlink" title="如何使用：Windows/Linux 平台"></a>如何使用：Windows/Linux 平台</h2><p>前往 <a href="https://github.com/obgnail/typora_plugin/issues/847">视频安装教程</a></p><ol><li><p><a href="https://github.com/obgnail/typora_plugin/releases/latest">下载</a> 插件源码的压缩包，并解压</p></li><li><p>进入 Typora 安装路径，找到包含 <code>window.html</code> 的文件夹 A</p><ul><li>正式版 Typora 对应的路径为 <code>./resources/window.html</code></li><li>免费版 Typora 对应的路径为 <code>./resources/app/window.html</code></li></ul></li><li><p>将解压得到的 plugin 文件夹粘贴进文件夹 A 下</p></li><li><p>进入文件夹 <code>A/plugin/bin/</code></p><ul><li>Windows 系统：右键 <code>install_windows.ps1</code> 文件，点击 <code>使用 PowerShell 运行</code></li><li>Linux 系统：以管理员运行 <code>install_linux.sh</code></li></ul></li><li><p>验证：重启 Typora，在正文区域点击鼠标右键，弹出右键菜单栏，如果能看到 <code>常用插件</code> 栏目，说明一切顺利</p></li></ol><table><thead><tr><th></th><th>正式版</th><th>免费版</th></tr></thead><tbody><tr><td>步骤 2-3</td><td><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/typora_dir_new.png" alt="typora_dir_new"></td><td><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/typora_dir_old.png" alt="typora_dir_old"></td></tr></tbody></table><table><thead><tr><th></th><th>Windows</th><th>Linux</th></tr></thead><tbody><tr><td>步骤 4</td><td><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/install_windows.png" alt="install_windows"></td><td><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/install_linux.png" alt="install_linux"></td></tr></tbody></table><h2 id="如何使用：archlinux-平台"><a href="#如何使用：archlinux-平台" class="headerlink" title="如何使用：archlinux 平台"></a>如何使用：archlinux 平台</h2><blockquote><p>目前此方法仅限 archlinux 平台，aur 见 <a href="https://aur.archlinux.org/packages/typora-plugin">aur/typora-plugin</a></p></blockquote><figure class="highlight sh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">yay -S typora-plugin<br></code></pre></td></tr></tbody></table></figure><h2 id="插件使用说明"><a href="#插件使用说明" class="headerlink" title="插件使用说明"></a>插件使用说明</h2><p>所有的插件都提供了四种使用方法：</p><ul><li>键盘党：<ul><li><code>Ctrl+J</code> 调出插件列表（详见 <code>toolbar</code> 插件）</li><li>快捷键（详见 <code>hotkeys</code> 插件）</li></ul></li><li>鼠标党：<ul><li>在正文区域右键调用（详见 <code>right_click_menu</code> 插件）</li><li>快捷按钮（详见 <code>quickButton</code> 插件）</li></ul></li></ul><h3 id="window-tab：标签页管理"><a href="#window-tab：标签页管理" class="headerlink" title="window_tab：标签页管理"></a>window_tab：标签页管理</h3><ul><li><code>切换标签</code>：Ctrl+滚轮滚动、ctrl+shift+tab、ctrl+tab、ctrl+PgUp、ctrl+PgDn</li><li><code>关闭标签</code>：ctrl+w、鼠标中键</li><li><code>新窗口打开</code>：ctrl+单击标签</li><li><code>排序标签</code>：拖拽</li><li><code>弹出标签的菜单选项</code>：右键单击标签页</li></ul><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/window_tab.gif" alt="window_tab"></p><h3 id="search-multi：多元文件搜索"><a href="#search-multi：多元文件搜索" class="headerlink" title="search_multi：多元文件搜索"></a>search_multi：多元文件搜索</h3><p>功能：搜索通过组合不同的条件来精确查找文件。</p><p>使用方式：</p><ul><li>方式一：右键菜单 -&gt; 常用插件 -&gt; 多元文件搜索</li><li>方式二：快捷键 <code>ctrl+shift+P</code></li></ul><p>使用示例：搜索语法类似于 Google 搜索语法，支持正则表达式。</p><table><thead><tr><th>输入</th><th>搜索文件</th></tr></thead><tbody><tr><td><code>pear</code></td><td>包含 pear</td></tr><tr><td><code>sour pear</code></td><td>包含 sour 和 pear</td></tr><tr><td><code>sour OR pear</code></td><td>包含 sour 或 pear</td></tr><tr><td><code>"sour pear"</code></td><td>包含 sour pear 词组</td></tr><tr><td><code>sour pear -apple</code></td><td>包含 sour 和 pear，且不含 apple</td></tr><tr><td><code>/\bsour\b/ pear mtime=2024-03-12</code></td><td>匹配正则 \bsour\b，且包含 pear，且文件的修改时间为 2024-03-12</td></tr><tr><td><code>frontmatter:开发 OR head=plugin OR strong:MIT</code></td><td>YAML Front Matter 包含开发 或者 标题内容为 plugin 或者 加粗文字包含 MIT</td></tr><tr><td><code>size&gt;10kb (linenum&gt;=1000 OR hasimage=true)</code></td><td>文件大小超过 10KB，并且文件要么至少有 1000 行，要么包含图片</td></tr><tr><td><code>thead:k8s h2:prometheus blockcode:"kubectl apply"</code></td><td>表头包含 k8s，且二级标题包含 prometheus，且代码块内容包含 kubectl apply</td></tr></tbody></table><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/search_mutli.gif" alt="search_mutli"></p><h3 id="collapse-paragraph：章节折叠"><a href="#collapse-paragraph：章节折叠" class="headerlink" title="collapse_paragraph：章节折叠"></a>collapse_paragraph：章节折叠</h3><p>功能：折叠 / 展开 章节下所有文本。支持折叠的标签：h1~h6。</p><ul><li><code>折叠/展开单个章节</code>：ctrl+click</li><li><code>折叠/展开父章节下所有同级的章节</code>：ctrl+alt+click</li><li><code>折叠/展开所有同级的章节</code>：ctrl+shift+alt+click</li></ul><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/collapse_paragraph.gif" alt="collapse_paragraph"></p><h3 id="collapse-list：列表折叠"><a href="#collapse-list：列表折叠" class="headerlink" title="collapse_list：列表折叠"></a>collapse_list：列表折叠</h3><p>功能：折叠 / 展开 无序列表、有序列表、任务列表。</p><h3 id="collapse-table：表格折叠"><a href="#collapse-table：表格折叠" class="headerlink" title="collapse_table：表格折叠"></a>collapse_table：表格折叠</h3><p>功能：折叠 / 展开 表格。</p><h3 id="md-padding：中英文混排优化"><a href="#md-padding：中英文混排优化" class="headerlink" title="md_padding：中英文混排优化"></a>md_padding：中英文混排优化</h3><p>功能：中英文混排时，中文与英文之间、中文与数字之间添加空格。</p><p>快捷键：ctrl+shift+B</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/md_padding.gif" alt="md_padding"></p><h3 id="slash-commands：斜杠命令"><a href="#slash-commands：斜杠命令" class="headerlink" title="slash_commands：斜杠命令"></a>slash_commands：斜杠命令</h3><p>功能：类似于 notion 的 slash command。</p><p>支持：</p><ul><li>插入文字片段（snippet）</li><li>插入组件</li><li>编辑样式</li><li>执行任意逻辑</li></ul><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/slash_commands.gif" alt="slash_commands"></p><h3 id="templater：文件模板功能"><a href="#templater：文件模板功能" class="headerlink" title="templater：文件模板功能"></a>templater：文件模板功能</h3><p>功能：类似于 obsidian 的文件模板功能，根据模板快速创建文件。</p><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; 文件模板。</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/templater.gif" alt="templater"></p><h3 id="resource-manager：一键清除无用图片"><a href="#resource-manager：一键清除无用图片" class="headerlink" title="resource_manager：一键清除无用图片"></a>resource_manager：一键清除无用图片</h3><p>功能：资源管理，清除无用图片</p><p>使用方式：右键菜单 -&gt; 少用插件 -&gt; 资源管理</p><h3 id="fence-enhance：复制，折叠，格式化代码"><a href="#fence-enhance：复制，折叠，格式化代码" class="headerlink" title="fence_enhance：复制，折叠，格式化代码"></a>fence_enhance：复制，折叠，格式化代码</h3><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/fence_enhance.png" alt="fence_enhance"></p><h3 id="toc：在右侧生成大纲目录"><a href="#toc：在右侧生成大纲目录" class="headerlink" title="toc：在右侧生成大纲目录"></a>toc：在右侧生成大纲目录</h3><p>功能：Typora 侧边栏的【文件】和【大纲】不能同时显示，为了解决此问题，此插件会在右侧新增一个【大纲】。</p><p>使用方式：</p><ul><li>方式一：常用插件 -&gt; 二级插件 -&gt; 大纲目录</li><li>方式二：右键点击侧边栏的【大纲】按钮</li></ul><h3 id="commander：命令行环境"><a href="#commander：命令行环境" class="headerlink" title="commander：命令行环境"></a>commander：命令行环境</h3><p>功能：类似于 total commander 的命令行，一个快速执行命令的工具，并提供少量交互。</p><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 命令行环境</p><p>支持 shell：</p><ul><li><code>cmd/bash</code>：Windows 或 Linux 的默认终端</li><li><code>powershell</code>：微软的傻儿子 :D</li><li><code>git bash</code>：需确保安装 Git Bash 并添加到环境变量</li><li><code>wsl</code>：需确保安装 WSL2 并添加到环境变量</li></ul><p>内置环境变量：</p><ul><li><code>$f</code>：当前文件路径</li><li><code>$d</code>：当前文件的所属目录</li><li><code>$m</code>：当前挂载的根目录</li></ul><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/commander.gif" alt="commander"></p><h3 id="markmap：提供-markmap-支持"><a href="#markmap：提供-markmap-支持" class="headerlink" title="markmap：提供 markmap 支持"></a>markmap：提供 markmap 支持</h3><p>使用方式：</p><ul><li>方式一：右键菜单 -&gt; 少用插件 -&gt; markmap</li><li>方式二：直接点击右下角的 markmap 按钮</li></ul><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/markmap.gif" alt="markmap"></p><h3 id="toolbar：多功能搜索"><a href="#toolbar：多功能搜索" class="headerlink" title="toolbar：多功能搜索"></a>toolbar：多功能搜索</h3><p>功能：类似于 vscode 的 ctrl+shift+p 功能</p><p>使用方式：</p><ul><li>方式一：右键菜单 -&gt; 少用插件 -&gt; 多功能搜索</li><li>方式二：快捷键 <code>ctrl+j</code></li></ul><p>支持搜索：</p><ul><li><code>his</code>：最新打开过的文件</li><li><code>plu</code>：插件</li><li><code>tab</code>：打开的标签页</li><li><code>ops</code>：常用操作</li><li><code>out</code>：文档大纲</li><li><code>mode</code>：切换文件模式</li><li><code>theme</code>：临时切换主题</li><li><code>func</code>：功能列表</li><li><code>all</code>：混合查找（所有项目都混在一起查找）</li></ul><p>键入内容说明：</p><ul><li>键入内容 = 搜索工具名称 + 空格 + 搜索内容</li><li>支持 <code>交集查询</code>、<code>差集查询</code>，并且可以随意组合（类似于 google 的正负向查询）</li></ul><p>举例：</p><ul><li><code>his node learn</code>：查找最近打开的文件，要求文件标题【包含 node 和 learn 两个关键字】</li><li><code>plu multi -search</code>：查找插件，要求插件名【包含 multi 关键字，但是不包含 search 关键字】</li><li><code>tab -messing</code>：查找所有打开的标签页，要求标签页名称【不包含 messing 关键字】</li><li><code>his close -win -mark 标签</code>：查找最近打开的文件，要求文件标题【包含 close、标签，不包含 win、mark】</li></ul><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/toolbar.gif" alt="toolbar"></p><h3 id="right-click-menu：右键菜单统一管理插件"><a href="#right-click-menu：右键菜单统一管理插件" class="headerlink" title="right_click_menu：右键菜单统一管理插件"></a>right_click_menu：右键菜单统一管理插件</h3><p>所有插件都支持在右键菜单中直接调用。鼠标党可以将右键菜单作为所有插件的主要调用方式。</p><h3 id="pie-menu：圆盘菜单"><a href="#pie-menu：圆盘菜单" class="headerlink" title="pie_menu：圆盘菜单"></a>pie_menu：圆盘菜单</h3><p>使用方式：</p><ul><li><code>弹出圆盘菜单</code>：Ctrl+鼠标右键</li><li><code>旋转圆盘菜单</code>：鼠标中键</li><li><code>固定圆盘菜单，圆盘不再自动消失</code>：鼠标左键圆心</li><li><code>展开圆盘菜单，圆盘不再自动收缩</code>：鼠标右键圆心</li></ul><h3 id="preferences：插件配置"><a href="#preferences：插件配置" class="headerlink" title="preferences：插件配置"></a>preferences：插件配置</h3><p>使用方式：右键菜单 -&gt; 少用插件 -&gt; 插件配置</p><h3 id="echarts：提供-echarts-支持"><a href="#echarts：提供-echarts-支持" class="headerlink" title="echarts：提供 echarts 支持"></a>echarts：提供 echarts 支持</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; Echarts</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/echarts.png" alt="echats"></p><h3 id="chart：提供-chartjs-支持"><a href="#chart：提供-chartjs-支持" class="headerlink" title="chart：提供 chartjs 支持"></a>chart：提供 chartjs 支持</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; Chart</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/chart.png" alt="chart"></p><h3 id="drawIO：提供-drawIO-组件支持"><a href="#drawIO：提供-drawIO-组件支持" class="headerlink" title="drawIO：提供 drawIO 组件支持"></a>drawIO：提供 drawIO 组件支持</h3><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/drawIO.png" alt="drawIO"></p><h3 id="abc：提供-abc-组件支持"><a href="#abc：提供-abc-组件支持" class="headerlink" title="abc：提供 abc 组件支持"></a>abc：提供 abc 组件支持</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; ABC</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/abcjs.png" alt="abcjs"></p><h3 id="calendar：-提供-tui-calendar-组件支持"><a href="#calendar：-提供-tui-calendar-组件支持" class="headerlink" title="calendar：  提供 tui.calendar 组件支持"></a>calendar：  提供 tui.calendar 组件支持</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; Calendar</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/calendar.png" alt="calendar"></p><h3 id="wavedrom：提供-wavedrom-组件支持"><a href="#wavedrom：提供-wavedrom-组件支持" class="headerlink" title="wavedrom：提供 wavedrom 组件支持"></a>wavedrom：提供 wavedrom 组件支持</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; Wavedrom</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/wavedrom.png" alt="wavedrom"></p><h3 id="marp：提供-marp-组件支持"><a href="#marp：提供-marp-组件支持" class="headerlink" title="marp：提供 marp 组件支持"></a>marp：提供 marp 组件支持</h3><p>功能：使用 markdown 做 PPT。</p><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; Marp</p><h3 id="plantUML：提供-PlantUML-组件支持"><a href="#plantUML：提供-PlantUML-组件支持" class="headerlink" title="plantUML：提供 PlantUML 组件支持"></a>plantUML：提供 PlantUML 组件支持</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; PlantUML</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/plantUML.png" alt="plantUML"></p><p>由于 plantUML 是 B/S 架构，需要用户提供渲染服务器。建议使用 Docker 安装渲染服务器：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker pull plantuml/plantuml-server:jetty<br>docker run -d --name plantuml-server -p 8080:8080 plantuml/plantuml-server:jetty<br></code></pre></td></tr></tbody></table></figure><h3 id="callouts：-提供-callouts-支持"><a href="#callouts：-提供-callouts-支持" class="headerlink" title="callouts：  提供 callouts 支持"></a>callouts：  提供 callouts 支持</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; Callouts</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/callouts.png" alt="callouts"></p><p>数量、类型、颜色、icon 皆可自己定义，请前往配置修改。</p><h3 id="kanban：看板"><a href="#kanban：看板" class="headerlink" title="kanban：看板"></a>kanban：看板</h3><p>拓展代码语法，添加看板功能。</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/kanban.png" alt="kanban"></p><h3 id="timeline：时间线"><a href="#timeline：时间线" class="headerlink" title="timeline：时间线"></a>timeline：时间线</h3><p>拓展代码语法，添加时间线功能。</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/timeline.png" alt="timeline"></p><h3 id="chat：聊天"><a href="#chat：聊天" class="headerlink" title="chat：聊天"></a>chat：聊天</h3><p>拓展代码语法，添加聊天功能。</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/chat.png" alt="chat"></p><h3 id="text-stylize：文字风格化"><a href="#text-stylize：文字风格化" class="headerlink" title="text_stylize：文字风格化"></a>text_stylize：文字风格化</h3><p>功能：将文字转为 HTML 格式，改变文字样式。</p><p>使用方式：右键菜单 -&gt; 少用插件 -&gt; 文字风格化。</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/text_stylize.gif" alt="text_stylize"></p><h3 id="read-only：只读模式"><a href="#read-only：只读模式" class="headerlink" title="read_only：只读模式"></a>read_only：只读模式</h3><p>功能：只读模式下文档不可编辑（开启后，右下角数字统计区域会出现 <code>ReadOnly</code> 字样）</p><p>快捷键：ctrl+shift+R</p><h3 id="blur：模糊模式"><a href="#blur：模糊模式" class="headerlink" title="blur：模糊模式"></a>blur：模糊模式</h3><p>功能：开启后，只有当前聚焦的组件可见，其余模糊。可以用于防偷窥。</p><p>使用方式：右键菜单 -&gt; 少用插件 -&gt; 模糊模式</p><blockquote><p>此插件只能于正式版 Typora 使用。</p></blockquote><h3 id="file-counter：显示文件数"><a href="#file-counter：显示文件数" class="headerlink" title="file_counter：显示文件数"></a>file_counter：显示文件数</h3><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/file_counter.png" alt="file_count"></p><h3 id="auto-number：自动编号"><a href="#auto-number：自动编号" class="headerlink" title="auto_number：自动编号"></a>auto_number：自动编号</h3><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/auto_number.png" alt="auto_number"></p><p>和其他使用 Theme CSS 的实现方式不同，此插件通过修改内置函数，完美解决导出 PDF 后侧边栏没有编号的问题 :)</p><h3 id="imageReviewer：图片查看器"><a href="#imageReviewer：图片查看器" class="headerlink" title="imageReviewer：图片查看器"></a>imageReviewer：图片查看器</h3><p>功能：一站式图片查看，并且提供简单图片编辑。</p><p>使用方式：</p><ul><li>方式一：点击右下角【查看图片】按钮</li><li>方式二：右键菜单 -&gt; 常用插件 -&gt;  二级插件 -&gt; 图片查看器</li></ul><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/image-reviewer.png" alt="image-reviewer"></p><h3 id="chineseSymbolAutoPairer：中文符号自动补全"><a href="#chineseSymbolAutoPairer：中文符号自动补全" class="headerlink" title="chineseSymbolAutoPairer：中文符号自动补全"></a>chineseSymbolAutoPairer：中文符号自动补全</h3><p>功能：输入 <code>《 【 （ ‘ “ 「</code> 符号时自动补全。</p><h3 id="datatables：表格增强"><a href="#datatables：表格增强" class="headerlink" title="datatables：表格增强"></a>datatables：表格增强</h3><p>功能：增强表格。提供搜索、过滤、分页、排序等功能。</p><p>使用方式：将光标定位在表格 -&gt; 右键菜单 -&gt; 少用插件 -&gt; 表格增强。</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/datatables.png" alt="datatables"></p><h3 id="resize-table：拖动调整表格大小"><a href="#resize-table：拖动调整表格大小" class="headerlink" title="resize_table：拖动调整表格大小"></a>resize_table：拖动调整表格大小</h3><p>功能：<code>ctrl+鼠标拖动</code>：修改表格的行高列宽。</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/resize_table.gif" alt="resize_table"></p><h3 id="resize-image：调整图片大小"><a href="#resize-image：调整图片大小" class="headerlink" title="resize_image：调整图片大小"></a>resize_image：调整图片大小</h3><p>功能：<code>alt+鼠标滚轮滚动</code>：调整图片大小。</p><h3 id="export-enhance：导出增强"><a href="#export-enhance：导出增强" class="headerlink" title="export_enhance：导出增强"></a>export_enhance：导出增强</h3><p>功能：导出 HTML 时，将图片转为 base64，避免图片丢失。</p><h3 id="sidebar-enhance：侧边栏增强"><a href="#sidebar-enhance：侧边栏增强" class="headerlink" title="sidebar_enhance：侧边栏增强"></a>sidebar_enhance：侧边栏增强</h3><p>功能：</p><ul><li>拖动大纲标题，调整文章结构</li><li>目录树显示其他扩展名文件</li><li>记忆大纲折叠状态</li><li>定制侧边栏文件图标</li></ul><h3 id="go-top：-一键到顶"><a href="#go-top：-一键到顶" class="headerlink" title="go_top： 一键到顶"></a>go_top： 一键到顶</h3><p>功能：在右下角添加一个一键到顶的按钮。</p><h3 id="dark：夜间模式"><a href="#dark：夜间模式" class="headerlink" title="dark：夜间模式"></a>dark：夜间模式</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 夜间模式</p><h3 id="no-image：无图模式"><a href="#no-image：无图模式" class="headerlink" title="no_image：无图模式"></a>no_image：无图模式</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 无图模式</p><h3 id="myopic-defocus：离焦视力舒缓"><a href="#myopic-defocus：离焦视力舒缓" class="headerlink" title="myopic_defocus：离焦视力舒缓"></a>myopic_defocus：离焦视力舒缓</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 离焦视力舒缓</p><h3 id="markdownLint：markdown-格式检查"><a href="#markdownLint：markdown-格式检查" class="headerlink" title="markdownLint：markdown 格式检查"></a>markdownLint：markdown 格式检查</h3><p>功能：检测当前文件是否符合 markdown 最佳实践规范。</p><p>使用方式：</p><ol><li>方法一：点击右上角的小方块</li><li>方法二：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; 格式检查</li></ol><h3 id="updater：一键升级插件"><a href="#updater：一键升级插件" class="headerlink" title="updater：一键升级插件"></a>updater：一键升级插件</h3><p>使用方式：右键菜单 -&gt; 少用插件 -&gt; 升级插件</p><blockquote><p>众所周知，有些用户并不能裸连 github 下载最新插件，故提供了设置代理功能（默认为系统代理）</p></blockquote><h3 id="easy-modify：编辑工具"><a href="#easy-modify：编辑工具" class="headerlink" title="easy_modify：编辑工具"></a>easy_modify：编辑工具</h3><p>使用方式：右键菜单 -&gt; 常用插件 -&gt; 编辑工具</p><p>本插件是常用的编辑工具集合，目前包括：</p><ol><li>复制标题路径</li><li>提升选中文段的标题等级</li><li>降低选中文段的标题等级</li><li>换行符 CRLF 转为 LF</li><li>换行符 LF 转为 CRLF</li><li>移除不可见字符</li><li>根据文档大纲一键生成思维导图：mindmap</li><li>根据文档大纲一键生成思维导图：graph</li><li>提取选区文字到新文件</li><li>添加结尾空格</li></ol><h3 id="editor-width-slider：写作区宽度调整"><a href="#editor-width-slider：写作区宽度调整" class="headerlink" title="editor_width_slider：写作区宽度调整"></a>editor_width_slider：写作区宽度调整</h3><p>使用方式：右键菜单 -&gt; 少用插件 -&gt; 写作区宽度调整</p><p>功能：调整写作区的宽度</p><h3 id="redirectLocalRootUrl：重定向本地资源根目录"><a href="#redirectLocalRootUrl：重定向本地资源根目录" class="headerlink" title="redirectLocalRootUrl：重定向本地资源根目录"></a>redirectLocalRootUrl：重定向本地资源根目录</h3><p>功能：如果你主要使用 obsidian 或 joplin 来管理文件，偶尔用 typora 打开文件。就会遇到一个问题：obsidian 或 joplin 都是将本地资源放在同一个目录中，这导致在 typora 打开后文件由于路径错误，无法访问本地资源。此插件就是为了解决此问题，重定向本地资源根目录。</p><blockquote><p>此插件默认关闭，需手动开启。</p></blockquote><h3 id="scrollBookmarker：-书签管理器"><a href="#scrollBookmarker：-书签管理器" class="headerlink" title="scrollBookmarker： 书签管理器"></a>scrollBookmarker： 书签管理器</h3><p>使用方式：</p><ol><li>使用 alt+click 正文内容，打上书签。</li><li>此时会自动调出书签管理器，点击上面的书签，即可跳转到书签。</li></ol><p>显示/隐藏书签管理器：右键菜单 -&gt; 常用插件 -&gt; 二级插件 -&gt; 书签管理器</p><h3 id="cipher：加密文件"><a href="#cipher：加密文件" class="headerlink" title="cipher：加密文件"></a>cipher：加密文件</h3><p>使用方式：右键菜单 -&gt; 少用插件 -&gt; 加密文件。</p><h3 id="truncate-text：暂时隐藏内容，提高大文件渲染性能"><a href="#truncate-text：暂时隐藏内容，提高大文件渲染性能" class="headerlink" title="truncate_text：暂时隐藏内容，提高大文件渲染性能"></a>truncate_text：暂时隐藏内容，提高大文件渲染性能</h3><p>功能：大文件在 Typora 的渲染性能很糟糕，用此插件暂时隐藏内容（只是隐藏显示，不修改文件），提高渲染性能。也可以用于防偷窥。</p><p>使用方式：右键菜单 -&gt; 少用插件 -&gt; 文本截断。</p><p>包含的功能如下：</p><ul><li>隐藏最前面：隐藏最前面的文本段，只留下最后 80 段。</li><li>重新显示：重新显示之前隐藏的所有文本段。</li><li>根据当前可视范围显示：根据当前可视范围显示文本段。</li></ul><blockquote><p>原理：通过设置 DOM 元素的 display 样式为 none 来隐藏元素，让元素不占用渲染树中的位置，对隐藏的元素操作不会引发其他元素的重排。</p></blockquote><h3 id="ripgrep：使用-ripgrep-搜索文件"><a href="#ripgrep：使用-ripgrep-搜索文件" class="headerlink" title="ripgrep：使用 ripgrep 搜索文件"></a>ripgrep：使用 ripgrep 搜索文件</h3><p>Typora 自带 ripgrep。此插件支持使用内建的 ripgrep 进行文件搜索。</p><blockquote><p>使用此插件需要您熟悉 ripgrep 工具。此插件默认关闭，需手动开启。</p></blockquote><h3 id="cursor-history：光标跳转"><a href="#cursor-history：光标跳转" class="headerlink" title="cursor_history：光标跳转"></a>cursor_history：光标跳转</h3><ul><li>上一个光标历史的快捷键：alt+←</li><li>下一个光标历史的快捷键：alt+→</li></ul><blockquote><p>此插件默认关闭，需手动开启。</p></blockquote><h3 id="static-markers：Markdown-标记常显"><a href="#static-markers：Markdown-标记常显" class="headerlink" title="static_markers：Markdown 标记常显"></a>static_markers：Markdown 标记常显</h3><p>告别格式刷新的干扰，让您的 Markdown 语法标记 <strong>始终可见、保持静态</strong>。</p><p>禁用所见即所得模式下的语法标记自动隐藏功能，让 **、##、_ 等所有 Markdown 标记像在源码模式中一样，永远清晰地展示在您的文本周围。</p><p><img src="https://raw.gitcode.com/gh_mirrors/ty/typora_plugin/files/master/assets/static_markers.png" alt="static_markers"></p><blockquote><p>此插件默认关闭，需手动开启。</p></blockquote><h3 id="hotkeys：快捷键注册中心（高级）"><a href="#hotkeys：快捷键注册中心（高级）" class="headerlink" title="hotkeys：快捷键注册中心（高级）"></a>hotkeys：快捷键注册中心（高级）</h3><blockquote><p>此插件是高级插件，仅对有 JavaScript 基础的用户开放。</p></blockquote><p>功能：以声明的形式，为【任意插件系统函数】或【任意自定义函数】绑定快捷键。</p><h3 id="quickButton：于右下角添加功能按钮（高级）"><a href="#quickButton：于右下角添加功能按钮（高级）" class="headerlink" title="quickButton：于右下角添加功能按钮（高级）"></a>quickButton：于右下角添加功能按钮（高级）</h3><blockquote><p>此插件是高级插件，仅对有 JavaScript 基础的用户开放。</p></blockquote><p>功能和 hotkeys 类似，以声明的形式，为【任意插件系统函数】设置快捷按钮。</p><h3 id="custom：开放平台，用户自定义插件（高级）"><a href="#custom：开放平台，用户自定义插件（高级）" class="headerlink" title="custom：开放平台，用户自定义插件（高级）"></a>custom：开放平台，用户自定义插件（高级）</h3><blockquote><p>此插件是高级插件，仅对有 JavaScript 基础的用户开放。</p></blockquote><p>功能：提供开放能力，支持用户自己写插件。</p><p>具体使用请参考 <a href="https://github.com/obgnail/typora_plugin/blob/master/plugin/custom/README.md">README.md</a>。</p><h3 id="json-rpc：外部操纵-Typora（高级）"><a href="#json-rpc：外部操纵-Typora（高级）" class="headerlink" title="json_rpc：外部操纵 Typora（高级）"></a>json_rpc：外部操纵 Typora（高级）</h3><p>功能：将包括 typora-plugin 所有功能在内的一切能力通过 <code>json-rpc</code> 的形式暴露出去，以供外部操纵 Typora。</p><p>具体使用请参考 <a href="https://github.com/obgnail/typora_plugin/blob/master/plugin/json_rpc/README.md">README.md</a>。</p><blockquote><p>此插件是高级插件，仅对开发人员开放。开启此插件后，外部将拥有 node、browser 两套环境，能完全控制电脑，因此如果您不是开发人员，请勿开启此插件。</p></blockquote><h3 id="article-uploader：上传博客文章"><a href="#article-uploader：上传博客文章" class="headerlink" title="article_uploader：上传博客文章"></a>article_uploader：上传博客文章</h3><p>功能：用户点击或者使用快捷键触发当前文章的自动发布功能，程序根据用户配置自动发布博客文章到各大平台</p><p>具体使用参考： <a href="https://github.com/obgnail/typora_plugin/blob/master/plugin/article_uploader/README.md">README.md</a>。以上传到 CSDN 为例，Gif 图如下：</p><p><img src="https://my-picture-bed1-1321100201.cos.ap-beijing.myqcloud.com/mypictures/CSDN%E6%88%90%E5%8A%9F%E6%BC%94%E7%A4%BA.gif" alt="CSDN 成功演示"></p><h2 id="致谢"><a href="#致谢" class="headerlink" title="致谢"></a>致谢</h2><ul><li>GPL: <a href="https://plantuml.com/">PlantUML</a> | <a href="https://chromewebstore.google.com/detail/refractify-myopic-defocus/dpnfdlnkgojjihdmgmacnmheflkojijm?hl=en">Refractify Myopic Defocus</a></li><li>Apache：<a href="https://echarts.apache.org/zh/index.html">ECharts</a> | <a href="https://github.com/jgraph/drawio">draw.io</a></li><li>MIT：<a href="https://markmap.js.org/">markmap</a> | <a href="https://www.chartjs.org/">Chart.js</a> | <a href="https://github.com/paulrosen/abcjs">abcjs</a> | <a href="https://github.com/nhn/tui.calendar">tui.calendar</a> | <a href="https://marp.app/">Marp</a> | <a href="https://wavedrom.com/">WaveDrom</a> | <a href="https://github.com/DataTables/DataTables">DataTables</a> | <a href="https://github.com/DavidAnson/markdownlint">markdownlint</a></li><li>no-licence：<a href="https://github.com/gatziourasd/typora-tabbar-plugin">typora-tabbar-plugin</a> | <a href="https://github.com/gruvw/typora-side-by-side">typora-side-by-side</a> | <a href="https://github.com/harttle/md-padding">md-padding</a></li></ul><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p><strong>本项目遵循 MIT 协议，请自由地享受。</strong></p><p>如果对各位有用的话，欢迎 star ⭐，欢迎推荐给你志同道合的朋友使用。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Typora-Plugin-README（中文）&quot;&gt;&lt;a href=&quot;#Typora-Plugin-README（中文）&quot; class=&quot;headerlink&quot; title=&quot;Typora Plugin README（中文）&quot;&gt;&lt;/a&gt;Typora Plugin </summary>
      
    
    
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>测试PicList上传图片到自建MinIO图库</title>
    <link href="https://www.qxz5637.top/2026/01/27/%E6%B5%8B%E8%AF%95PicList%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87%E5%88%B0%E8%87%AA%E5%BB%BAMinIO%E5%9B%BE%E5%BA%93/"/>
    <id>https://www.qxz5637.top/2026/01/27/%E6%B5%8B%E8%AF%95PicList%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87%E5%88%B0%E8%87%AA%E5%BB%BAMinIO%E5%9B%BE%E5%BA%93/</id>
    <published>2026-01-26T16:00:00.000Z</published>
    <updated>2026-01-27T13:22:44.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="测试-PicList-上传图片到自建-MinIO-图库"><a href="#测试-PicList-上传图片到自建-MinIO-图库" class="headerlink" title="测试 PicList 上传图片到自建 MinIO 图库"></a>测试 PicList 上传图片到自建 MinIO 图库</h1><h4 id="如果能够看到下方的图片，就说明配置成功了！"><a href="#如果能够看到下方的图片，就说明配置成功了！" class="headerlink" title="如果能够看到下方的图片，就说明配置成功了！"></a><span style="font-weight:bold;">如果能够看到下方的图片，就说明配置成功了！</span></h4><p><img src="https://img.qxz5637.top/images/qexo/2026/01/27/a4740926ebcb659cdc20fda71511f0ef.jpg" alt="美女"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;测试-PicList-上传图片到自建-MinIO-图库&quot;&gt;&lt;a href=&quot;#测试-PicList-上传图片到自建-MinIO-图库&quot; class=&quot;headerlink&quot; title=&quot;测试 PicList 上传图片到自建 MinIO 图库&quot;&gt;&lt;/a&gt;测试 Pi</summary>
      
    
    
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>从零到英雄：打造你的终极AI、NAS与虚拟化母舰</title>
    <link href="https://www.qxz5637.top/2025/10/22/%E4%BB%8E%E9%9B%B6%E5%88%B0%E8%8B%B1%E9%9B%84%EF%BC%9A%E6%89%93%E9%80%A0%E4%BD%A0%E7%9A%84%E7%BB%88%E6%9E%81AI%E3%80%81NAS%E4%B8%8E%E8%99%9A%E6%8B%9F%E5%8C%96%E6%AF%8D%E8%88%B0/"/>
    <id>https://www.qxz5637.top/2025/10/22/%E4%BB%8E%E9%9B%B6%E5%88%B0%E8%8B%B1%E9%9B%84%EF%BC%9A%E6%89%93%E9%80%A0%E4%BD%A0%E7%9A%84%E7%BB%88%E6%9E%81AI%E3%80%81NAS%E4%B8%8E%E8%99%9A%E6%8B%9F%E5%8C%96%E6%AF%8D%E8%88%B0/</id>
    <published>2025-10-21T16:16:54.369Z</published>
    <updated>2025-10-21T16:46:09.513Z</updated>
    
    <content type="html"><![CDATA[<h1 id="从零到英雄：打造你的终极AI、NAS与虚拟化母舰"><a href="#从零到英雄：打造你的终极AI、NAS与虚拟化母舰" class="headerlink" title="从零到英雄：打造你的终极AI、NAS与虚拟化母舰"></a>从零到英雄：打造你的终极AI、NAS与虚拟化母舰</h1><h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><h3 id="项目愿景"><a href="#项目愿景" class="headerlink" title="项目愿景"></a>项目愿景</h3><p>本教程旨在提供一份从零开始的、详尽的服务器部署指南。我们将以一个纯净的Ubuntu Server系统为起点，逐步将其打造成一台功能强大、性能卓越的多功能家庭服务器。这台服务器将集多种核心能力于一身：作为家庭数据中心，它将通过ZFS提供企业级的安全存储（NAS）；作为影音娱乐中枢，它将提供高性能的媒体服务；作为灵活的实验平台，它将支持KVM全系统虚拟化；而最激动人心的是，它将成为一台7x24小时待命的AI推理引擎，充分释放多GPU的澎湃算力。</p><h3 id="技术栈概览"><a href="#技术栈概览" class="headerlink" title="技术栈概览"></a>技术栈概览</h3><p>本次部署将围绕以下经过精心挑选的核心技术构建，它们均以其稳定性、高性能和强大的社区支持而著称：</p><ul><li><strong>操作系统</strong>: Ubuntu Server 22.04 LTS</li><li><strong>文件系统与存储</strong>: ZFS (RAID-Z)</li><li><strong>网络文件共享</strong>: Samba (SMB/CIFS)</li><li><strong>应用容器化</strong>: Docker Engine &amp; Portainer</li><li><strong>虚拟化平台</strong>: KVM &amp; Cockpit</li><li><strong>GPU计算平台</strong>: AMD ROCm (Radeon Open Compute)</li><li><strong>AI应用</strong>: Ollama</li></ul><h3 id="本指南面向的读者"><a href="#本指南面向的读者" class="headerlink" title="本指南面向的读者"></a>本指南面向的读者</h3><p>本教程专为具备Linux命令行基础操作知识，并渴望构建一套复杂、多层级、遵循业界最佳实践的家庭服务器的用户而设计。我们将深入每个技术细节，确保您不仅能成功复现整个搭建过程，更能深刻理解其底层原理。</p><hr><h2 id="第零部分：系统安装-—-Ubuntu-Server-22-04-LTS-基础"><a href="#第零部分：系统安装-—-Ubuntu-Server-22-04-LTS-基础" class="headerlink" title="第零部分：系统安装 — Ubuntu Server 22.04 LTS 基础"></a>第零部分：系统安装 — Ubuntu Server 22.04 LTS 基础</h2><p>一个稳定、纯净的操作系统是一切服务的基石。我们将从制作系统启动盘开始，完成Ubuntu Server 22.04 LTS的安装。</p><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><ol><li><strong>获取系统镜像</strong>: 前往Ubuntu官方网站，下载<code>Ubuntu Server 22.04.4 LTS</code>或更新的LTS版本ISO镜像文件。</li><li><strong>制作启动盘</strong>: 使用Rufus、Balena Etcher或Ventoy等工具，将下载的ISO镜像写入一个U盘。</li><li><strong>最佳实践：独立的系统盘</strong>: 强烈建议为操作系统准备一块独立的、小容量的高速驱动器（如SATA SSD或NVMe SSD）。将操作系统与数据存储池物理分离，可以极大地提升系统响应速度，并简化未来的管理、备份与恢复流程，是构建可靠服务器的黄金法则。</li></ol><h3 id="关键安装步骤"><a href="#关键安装步骤" class="headerlink" title="关键安装步骤"></a>关键安装步骤</h3><p>将制作好的U盘插入服务器，开机并从U盘引导，进入Ubuntu安装程序。以下是需要特别注意的关键配置步骤：</p><ul><li><strong>语言 (Language)</strong>: 建议选择<code>English</code>，以避免在终端环境中可能出现的字符编码问题。</li><li><strong>键盘布局 (Keyboard layout)</strong>: 保持默认的<code>English (US)</code>即可。</li><li><strong>网络配置 (Network configuration)</strong>: 确保服务器已通过网线连接到您的路由器。安装程序会自动通过DHCP获取IP地址，这是后续进行远程管理的前提。</li><li><strong>存储布局 (Storage configuration)</strong>: 这是<strong>至关重要</strong>的一步。<ul><li>选择 <code>Custom storage layout</code>（自定义存储布局）。</li><li>在磁盘列表中，精确地选择您为操作系统准备的那块独立SSD。</li><li>将其格式化为<code>ext4</code>文件系统，并挂载到根目录<code>/</code>。</li><li><strong>请务必不要对计划用于ZFS阵列的大容量数据硬盘进行任何操作。</strong></li></ul></li><li><strong>用户配置 (Profile setup)</strong>: 创建您的管理员账户。例如，用户名为<code>spoto</code>，并设置一个足够强度的密码。这个账户将是您未来通过SSH登录和管理服务器的唯一身份。</li><li><strong>安装OpenSSH服务 (Install OpenSSH server)</strong>: <strong>此项为必选项。</strong> 务必勾选<code>Install OpenSSH server</code>。这将允许您在系统安装完成后，从局域网内的任何电脑通过SSH远程连接服务器，实现“无头”（Headless）管理，不再需要为服务器长期连接显示器和键盘。</li><li><strong>预装软件 (Featured server snaps)</strong>: 为保持系统纯净，此处我们<strong>不选择任何预装的snap软件包</strong>。直接按<code>Tab</code>键跳转到<code>Done</code>并回车。</li></ul><p>完成以上步骤后，安装程序将自动进行。待进度条走完，系统会提示您移除U盘并重启。</p><h3 id="首次启动与远程接入"><a href="#首次启动与远程接入" class="headerlink" title="首次启动与远程接入"></a>首次启动与远程接入</h3><p>服务器重启后，您会看到一个命令行的登录提示符。至此，物理层面的操作已经结束。现在，您需要找到服务器的IP地址（通常可以在路由器的管理界面中的DHCP客户端列表里找到），然后回到您的工作电脑上，打开终端或SSH客户端，使用以下命令进行连接：</p><figure class="highlight angelscript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs angelscript">ssh <span class="hljs-symbol">spoto@<span class="hljs-keyword">&lt;your_server_ip&gt;</span></span><br></code></pre></td></tr></tbody></table></figure><p>输入您在安装时设置的密码，成功登录后，您就正式开启了这台服务器的配置之旅。</p><hr><h2 id="第一部分：存储基石-—-ZFS部署"><a href="#第一部分：存储基石-—-ZFS部署" class="headerlink" title="第一部分：存储基石 — ZFS部署"></a>第一部分：存储基石 — ZFS部署</h2><p>ZFS不仅仅是一个文件系统，它是一个集成了逻辑卷管理和文件系统的先进存储平台，以其无与伦比的数据完整性、内置RAID功能和强大的快照机制而闻名。</p><h3 id="第一步：安装ZFS工具包"><a href="#第一步：安装ZFS工具包" class="headerlink" title="第一步：安装ZFS工具包"></a>第一步：安装ZFS工具包</h3><p>首先，更新系统软件包列表并安装<code>zfsutils-linux</code>，这个软件包包含了在Linux上管理ZFS所需的所有命令行工具 。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> apt update &amp;&amp; <span class="hljs-built_in">sudo</span> apt upgrade -y<br><span class="hljs-built_in">sudo</span> apt install -y zfsutils-linux<br></code></pre></td></tr></tbody></table></figure><h3 id="第二步：精确识别硬盘"><a href="#第二步：精确识别硬盘" class="headerlink" title="第二步：精确识别硬盘"></a>第二步：精确识别硬盘</h3><p>在创建存储池之前，必须准确地识别出用于数据存储的硬盘。</p><p>lsblk -o name,size,model<br>这个命令会清晰地列出所有块设备及其名称、容量和型号，方便您确认目标硬盘 。</p><h3 id="第三步：创建raidz存储池"><a href="#第三步：创建raidz存储池" class="headerlink" title="第三步：创建raidz存储池"></a>第三步：创建<code>raidz</code>存储池</h3><p>创建ZFS存储池（zpool）是核心步骤。然而，直接使用<code>/dev/sdX</code>这样的设备名是一个常见的、但存在严重隐患的做法。Linux内核在每次启动时动态分配这些名称，顺序可能会因为硬件改动或启动时序的微小变化而改变，这会导致ZFS存储池导入失败，使您的数据面临风险。</p><p>专业的做法是使用持久化的设备标识符。这些标识符基于硬盘的物理属性（如序列号），永远不会改变。</p><p><strong>查找持久化ID</strong>:</p><figure class="highlight stata"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs stata"><span class="hljs-keyword">ls</span> -<span class="hljs-keyword">la</span> /dev/disk/<span class="hljs-keyword">by</span>-id/<br></code></pre></td></tr></tbody></table></figure><ol><li>这个命令会列出一系列指向实际设备（如<code>../../sdb</code>）的符号链接。请选择那些以<code>ata-</code>或<code>nvme-</code>开头的、包含了您的硬盘型号和序列号的、并且不含<code>-partX</code>后缀的完整ID。</li></ol><p><strong>使用持久化ID创建存储池</strong>: 假设您有四块8TB的硬盘，准备创建一个<code>raidz</code>（类似RAID 5，允许单盘故障）存储池，并将其命名为<code>tank</code>。命令如下（请将示例ID替换为您自己的硬盘ID）：</p><p>sudo zpool create -f tank raidz /dev/disk/by-id/ata-WDC_WD80EFZZ-68BTXN0_SERIAL1 /dev/disk/by-id/ata-WDC_WD80EFZZ-68BTXN0_SERIAL2 /dev/disk/by-id/ata-WDC_WD80EFZZ-68BTXN0_SERIAL3 /dev/disk/by-id/ata-WDC_WD80EFZZ-68BTXN0_SERIAL4</p><ol><li>下表详细解释了该命令的各个组成部分：</li></ol><table><thead><tr><th>参数</th><th>描述</th></tr></thead><tbody><tr><td>sudo zpool create</td><td>以管理员权限执行创建新ZFS存储池的命令。</td></tr><tr><td>-f</td><td><strong>强制 (Force)</strong>。如果目标硬盘上存在残留的分区表或文件系统，此参数将强制覆盖。<strong>请仅在确认硬盘数据不再需要时使用。</strong></td></tr><tr><td>tank</td><td>为新创建的存储池指定的名称。您可以自定义，tank是一个常用名。</td></tr><tr><td>raidz</td><td>指定存储池的RAID级别。raidz即RAID-Z1，提供单盘冗余。对于4块硬盘，总可用容量约为3块硬盘之和。</td></tr><tr><td>/dev/disk/by-id/…</td><td>构成存储池的成员硬盘列表。使用持久化ID是确保系统长期稳定运行的最佳实践。</td></tr></tbody></table><p>导出到 Google 表格</p><h3 id="第四步：检查存储池状态"><a href="#第四步：检查存储池状态" class="headerlink" title="第四步：检查存储池状态"></a>第四步：检查存储池状态</h3><p>创建完成后，立即使用<code>zpool status</code>命令检查其健康状况 。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> zpool status<br></code></pre></td></tr></tbody></table></figure><p>一个健康的存储池会显示<code>state: ONLINE</code>以及<code>errors: No known data errors</code>。这是您需要关注的核心指标。</p><h3 id="第五步：使用数据集与快照进行灵活管理"><a href="#第五步：使用数据集与快照进行灵活管理" class="headerlink" title="第五步：使用数据集与快照进行灵活管理"></a>第五步：使用数据集与快照进行灵活管理</h3><p>ZFS的强大之处在于其“数据集”（Dataset）概念。数据集可以被看作是智能的子目录或独立的文件系统，可以对每个数据集单独设置压缩、配额、加密等属性。</p><p><strong>创建数据集</strong>: 我们将为Docker的持久化数据和媒体文件分别创建数据集。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> zfs create tank/docker<br><span class="hljs-built_in">sudo</span> zfs create tank/media<br></code></pre></td></tr></tbody></table></figure><p><strong>ZFS的“后悔药”——快照</strong>: 快照是ZFS文件系统在特定时间点的只读镜像。创建快照几乎是瞬时完成的，且初始不占用额外空间。它为您提供了一个强大的回滚机制。</p><p>sudo zfs snapshot tank/docker@initial-setup</p><ol><li>这个命令为<code>tank/docker</code>数据集创建了一个名为<code>initial-setup</code>的快照。如果后续配置出错，可以轻松回滚到这个状态。</li></ol><hr><h2 id="第二部分：网络枢纽-—-SMB文件共享"><a href="#第二部分：网络枢纽-—-SMB文件共享" class="headerlink" title="第二部分：网络枢纽 — SMB文件共享"></a>第二部分：网络枢纽 — SMB文件共享</h2><p>Samba是在Linux系统上实现SMB/CIFS协议的标准软件，它能让您的服务器无缝地与Windows、macOS等客户端进行文件共享。</p><h3 id="第一步：安装与配置Samba"><a href="#第一步：安装与配置Samba" class="headerlink" title="第一步：安装与配置Samba"></a>第一步：安装与配置Samba</h3><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> apt install -y samba<br><span class="hljs-built_in">sudo</span> nano /etc/samba/smb.conf<br></code></pre></td></tr></tbody></table></figure><p>使用<code>nano</code>编辑器打开主配置文件，在文件末尾添加以下内容，来定义一个名为<code>[media]</code>的网络共享，它将指向我们之前创建的<code>/tank/media</code>数据集 。</p><p>Ini, TOML</p><figure class="highlight abnf"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs abnf">[media]<br>   comment <span class="hljs-operator">=</span> Server Media Files<br>   path <span class="hljs-operator">=</span> /tank/media<br>   browseable <span class="hljs-operator">=</span> yes<br>   writable <span class="hljs-operator">=</span> yes<br>   guest ok <span class="hljs-operator">=</span> no<br>   read only <span class="hljs-operator">=</span> no<br>   create mask <span class="hljs-operator">=</span> <span class="hljs-number">0664</span><br>   directory mask <span class="hljs-operator">=</span> <span class="hljs-number">0775</span><br></code></pre></td></tr></tbody></table></figure><p>下表解释了每个配置项的含义：</p><table><thead><tr><th>指令</th><th>值</th><th>描述</th></tr></thead><tbody><tr><td>[media]</td><td>-</td><td>定义了共享的名称，这将是网络上可见的文件夹名。</td></tr><tr><td>comment</td><td>Server Media Files</td><td>对该共享的描述性注释。</td></tr><tr><td>path</td><td>/tank/media</td><td>指定服务器上被共享的目录的绝对路径。</td></tr><tr><td>browseable</td><td>yes</td><td>允许此共享在网络邻居中被浏览到。</td></tr><tr><td>writable</td><td>yes</td><td>允许授权用户在此共享中创建和修改文件。</td></tr><tr><td>guest ok</td><td>no</td><td>禁止匿名访问，用户必须提供有效的用户名和密码。</td></tr><tr><td>read only</td><td>no</td><td>与writable = yes功能重叠，但明确表示该共享是可写的。</td></tr><tr><td>create mask</td><td>0664</td><td>为新创建的文件设置默认权限，即-rw-rw-r–。</td></tr><tr><td>directory mask</td><td>0775</td><td>为新创建的目录设置默认权限，即drwxrwxr-x。</td></tr></tbody></table><p>导出到 Google 表格</p><h3 id="第二步：管理用户与权限"><a href="#第二步：管理用户与权限" class="headerlink" title="第二步：管理用户与权限"></a>第二步：管理用户与权限</h3><p>Samba使用独立于Linux系统的密码数据库。我们需要将系统用户添加到Samba中，并为其设置一个专用的访问密码。</p><p><strong>添加Samba用户</strong>: 为我们之前创建的<code>spoto</code>用户设置Samba密码。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> smbpasswd -a spoto<br></code></pre></td></tr></tbody></table></figure><ol><li>系统会提示您输入并确认该用户的Samba密码。</li></ol><p><strong>设置文件系统权限</strong>: 确保<code>spoto</code>用户对共享目录<code>/tank/media</code>拥有读写权限。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> <span class="hljs-built_in">chown</span> -R spoto:spoto /tank/media<br></code></pre></td></tr></tbody></table></figure><h3 id="第三步：应用配置并测试"><a href="#第三步：应用配置并测试" class="headerlink" title="第三步：应用配置并测试"></a>第三步：应用配置并测试</h3><p>重启Samba服务使所有配置生效。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> systemctl restart smbd<br></code></pre></td></tr></tbody></table></figure><p>现在，您可以从局域网内的任何一台Windows电脑，在文件资源管理器地址栏输入<code>\\&lt;your_server_ip&gt;\media</code>，或在macOS的Finder中使用<code>Command+K</code>并输入<code>smb://&lt;your_server_ip&gt;/media</code>，然后使用<code>spoto</code>用户名和您刚刚设置的Samba密码进行访问。</p><hr><h2 id="第三部分：性能核心-—-安装AMD-ROCm驱动"><a href="#第三部分：性能核心-—-安装AMD-ROCm驱动" class="headerlink" title="第三部分：性能核心 — 安装AMD ROCm驱动"></a>第三部分：性能核心 — 安装AMD ROCm驱动</h2><p>ROCm (Radeon Open Compute) 是AMD官方的开源GPU计算平台，是让Ollama等AI应用能够利用AMD GPU进行加速运算的必要驱动和软件栈。安装过程必须严谨，遵循官方推荐流程。</p><h3 id="第一步：系统更新与依赖准备"><a href="#第一步：系统更新与依赖准备" class="headerlink" title="第一步：系统更新与依赖准备"></a>第一步：系统更新与依赖准备</h3><p>首先，确保系统是最新状态，并安装一些必要的辅助工具。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> apt update &amp;&amp; <span class="hljs-built_in">sudo</span> apt upgrade -y<br><span class="hljs-built_in">sudo</span> apt install -y wget gpg<br></code></pre></td></tr></tbody></table></figure><h3 id="第二步：添加AMD官方GPG密钥与软件源"><a href="#第二步：添加AMD官方GPG密钥与软件源" class="headerlink" title="第二步：添加AMD官方GPG密钥与软件源"></a>第二步：添加AMD官方GPG密钥与软件源</h3><p>GPU驱动这类底层软件，版本兼容性至关重要。直接从AMD的官方软件仓库安装，是确保获取最新、最稳定版本的唯一可靠方法 。脚本中简单的</p><p><code>apt install rocm</code>是不完整的，正确的步骤如下：</p><p><strong>导入AMD的GPG公钥</strong>，用于验证软件包的真实性：</p><figure class="highlight awk"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs awk">wget -qO - https:<span class="hljs-regexp">//</span>repo.radeon.com<span class="hljs-regexp">/rocm/</span>rocm.gpg.key | \<br>gpg --dearmor | sudo tee <span class="hljs-regexp">/etc/</span>apt<span class="hljs-regexp">/keyrings/</span>rocm.gpg &gt; <span class="hljs-regexp">/dev/</span>null<br></code></pre></td></tr></tbody></table></figure><p><strong>将ROCm的软件仓库地址添加到系统的apt源列表</strong>。请注意，命令中的<code>6.1.2</code>是编写本教程时的稳定版本号，您应访问AMD ROCm官方文档，获取当前最新的版本号进行替换。对于Ubuntu 22.04 (<code>jammy</code>)，命令如下：</p><figure class="highlight apache"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">echo</span> <span class="hljs-string">"deb [arch=amd64 signed-by=/etc/apt/keyrings/rocm.gpg] https://repo.radeon.com/rocm/apt/6.1.2/ jammy main"</span> <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span><br></code></pre></td></tr></tbody></table></figure><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> <span class="hljs-built_in">tee</span> /etc/apt/sources.list.d/rocm.list <br></code></pre></td></tr></tbody></table></figure><h3 id="第三步：安装ROCm核心软件包"><a href="#第三步：安装ROCm核心软件包" class="headerlink" title="第三步：安装ROCm核心软件包"></a>第三步：安装ROCm核心软件包</h3><p>添加完软件源后，刷新软件包列表并安装<code>rocm</code>这个元软件包，它会自动处理所有相关的依赖项。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> apt update<br><span class="hljs-built_in">sudo</span> apt install -y rocm<br></code></pre></td></tr></tbody></table></figure><h3 id="第四步：配置用户权限"><a href="#第四步：配置用户权限" class="headerlink" title="第四步：配置用户权限"></a>第四步：配置用户权限</h3><p>为了让普通用户（非root）能够调用GPU进行计算和渲染，必须将其加入<code>render</code>和<code>video</code>用户组。这是一个非常关键且容易被忽略的步骤 。</p><figure class="highlight stylus"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs stylus">sudo usermod -<span class="hljs-selector-tag">a</span> -G render,<span class="hljs-selector-tag">video</span> <span class="hljs-variable">$LOGNAME</span><br></code></pre></td></tr></tbody></table></figure><p><code>$LOGNAME</code>是一个环境变量，会自动替换为当前登录的用户名（例如<code>spoto</code>）。</p><h3 id="第五步：重启并验证安装"><a href="#第五步：重启并验证安装" class="headerlink" title="第五步：重启并验证安装"></a>第五步：重启并验证安装</h3><p>驱动和权限的变更需要一次完整的系统重启才能完全生效。<strong>此步骤不可省略</strong> 。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> reboot<br></code></pre></td></tr></tbody></table></figure><p>服务器重启后，重新通过SSH登录，然后使用以下两个命令来验证ROCm是否安装成功：</p><ol><li><code>rocminfo</code>: 这个命令会输出大量关于系统HSA（异构系统架构）代理的详细信息，如果能看到您的GPU被列出，说明驱动已初步识别硬件。</li></ol><p><code>rocm-smi</code>: 这是AMD版的<code>nvidia-smi</code>，是最终的验证工具。</p><figure class="highlight ebnf"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">rocm-smi</span><br></code></pre></td></tr></tbody></table></figure><p>如果<code>rocm-smi</code>成功执行并输出一个清晰的表格，列出了您所有的AMD GPU（例如三张MI50）、它们的温度、显存使用情况和功耗，那么恭喜您，最关键的驱动部分已经完美配置成功！</p><hr><h2 id="第四部分：应用层-—-Docker与Portainer"><a href="#第四部分：应用层-—-Docker与Portainer" class="headerlink" title="第四部分：应用层 — Docker与Portainer"></a>第四部分：应用层 — Docker与Portainer</h2><p>Docker是当今最流行的容器化技术，它能将应用及其所有依赖打包到一个轻量、可移植的容器中，彻底解决了“在我电脑上能跑”的难题。Portainer则为Docker提供了一个美观、强大的Web管理界面。</p><h3 id="第一步：安装Docker引擎"><a href="#第一步：安装Docker引擎" class="headerlink" title="第一步：安装Docker引擎"></a>第一步：安装Docker引擎</h3><p>与ROCm驱动一样，我们应该使用Docker官方的软件源来安装Docker引擎（<code>docker-ce</code>），而不是使用Ubuntu自带仓库中可能过时的<code>docker.io</code>版本 。</p><p><strong>设置Docker官方</strong><code>apt</code><strong>仓库</strong>: 这个过程包含添加GPG密钥和软件源地址，请依次执行以下命令：</p><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 安装依赖包</span><br><span class="hljs-built_in">sudo</span> apt-get install -y ca-certificates curl<br><span class="hljs-built_in">sudo</span> install -m 0755 -d /etc/apt/keyrings<br><span class="hljs-comment"># 添加Docker的GPG密钥</span><br><span class="hljs-built_in">sudo</span> curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc<br><span class="hljs-built_in">sudo</span> <span class="hljs-built_in">chmod</span> a+r /etc/apt/keyrings/docker.asc<br><br><span class="hljs-comment"># 添加仓库到apt源</span><br><span class="hljs-built_in">echo</span> \<br>  <span class="hljs-string">"deb [arch=<span class="hljs-subst">$(dpkg --print-architecture)</span> signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \</span><br><span class="hljs-string">  <span class="hljs-subst">$(. /etc/os-release &amp;&amp; echo <span class="hljs-string">"<span class="hljs-variable">$VERSION_CODENAME</span>"</span>)</span> stable"</span> | \<br>  <span class="hljs-built_in">sudo</span> <span class="hljs-built_in">tee</span> /etc/apt/sources.list.d/docker.list &gt; /dev/null<br><span class="hljs-built_in">sudo</span> apt-get update<br></code></pre></td></tr></tbody></table></figure><p><strong>安装Docker引擎</strong>: 执行以下命令安装最新版的Docker Community Edition及其相关组件 。</p><figure class="highlight stata"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs stata">sudo apt-get install -y docker-ce docker-ce-<span class="hljs-keyword">cli</span> containerd.io docker-buildx-<span class="hljs-keyword">plugin</span> docker-compose-<span class="hljs-keyword">plugin</span><br></code></pre></td></tr></tbody></table></figure><h3 id="第二步：Docker安装后配置"><a href="#第二步：Docker安装后配置" class="headerlink" title="第二步：Docker安装后配置"></a>第二步：Docker安装后配置</h3><p>默认情况下，执行<code>docker</code>命令需要<code>sudo</code>权限。为了方便日常使用，我们将当前用户添加到<code>docker</code>用户组 。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> usermod -aG docker <span class="hljs-variable">$LOGNAME</span><br></code></pre></td></tr></tbody></table></figure><p>为了让用户组的变更在当前SSH会话中立即生效，而无需重新登录，可以执行<code>newgrp</code>命令：</p><figure class="highlight ebnf"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">newgrp docker</span><br></code></pre></td></tr></tbody></table></figure><h3 id="第三步：部署Portainer管理面板"><a href="#第三步：部署Portainer管理面板" class="headerlink" title="第三步：部署Portainer管理面板"></a>第三步：部署Portainer管理面板</h3><p>一行命令即可部署Portainer。</p><figure class="highlight apache"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">docker</span> volume create portainer_data<br><span class="hljs-attribute">docker</span> run -d -p <span class="hljs-number">8000</span>:<span class="hljs-number">8000</span> -p <span class="hljs-number">9443</span>:<span class="hljs-number">9443</span> --name portainer --restart=always <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>-v /var/run/docker.sock:/var/run/docker.sock <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>-v portainer_data:/data <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>portainer/portainer-ce:latest<br></code></pre></td></tr></tbody></table></figure><p>这条命令中的<code>-v /var/run/docker.sock:/var/run/docker.sock</code>是关键，它将主机上的Docker守护进程套接字文件映射到Portainer容器内部，从而授权Portainer管理主机上的所有Docker活动 。</p><p>部署完成后，通过浏览器访问<code>https://&lt;your_server_ip&gt;:9443</code>，即可进入Portainer的初始化设置界面。</p><hr><h2 id="第五部分：Docker实战-—-部署Jellyfin并开启硬件转码"><a href="#第五部分：Docker实战-—-部署Jellyfin并开启硬件转码" class="headerlink" title="第五部分：Docker实战 — 部署Jellyfin并开启硬件转码"></a>第五部分：Docker实战 — 部署Jellyfin并开启硬件转码</h2><p>Jellyfin是一款优秀的开源媒体服务器。结合我们强大的MI50计算卡，它可以实现高性能的4K视频硬件转码，让您在任何设备上都能流畅观影。</p><h3 id="第一步：在ZFS上准备存储目录"><a href="#第一步：在ZFS上准备存储目录" class="headerlink" title="第一步：在ZFS上准备存储目录"></a>第一步：在ZFS上准备存储目录</h3><p>在<code>tank/media</code>数据集中为不同类型的媒体创建子目录，并在<code>tank/docker</code>数据集中为Jellyfin的配置文件创建一个专用目录。</p><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><span class="hljs-built_in">mkdir</span> -p /tank/media/movies<br><span class="hljs-built_in">mkdir</span> -p /tank/media/tvshows<br><span class="hljs-built_in">mkdir</span> -p /tank/docker/jellyfin_config<br></code></pre></td></tr></tbody></table></figure><p>将Docker应用的配置文件（持久化数据）存放在ZFS数据集上，有一个巨大的优势：您可以利用ZFS快照功能为应用配置提供强大的安全保障。例如，在升级Jellyfin容器版本之前，执行<code>sudo zfs snapshot tank/docker/jellyfin_config@before-update</code>。如果新版本出现问题，只需一条<code>rollback</code>命令即可将所有配置瞬间恢复到升级前的状态。</p><h3 id="第二步：部署Jellyfin容器"><a href="#第二步：部署Jellyfin容器" class="headerlink" title="第二步：部署Jellyfin容器"></a>第二步：部署Jellyfin容器</h3><p>执行以下<code>docker run</code>命令来启动Jellyfin。</p><figure class="highlight apache"><table><tbody><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><code class="hljs apache"><span class="hljs-attribute">docker</span> run -d <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  --name jellyfin <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  -p <span class="hljs-number">8096</span>:<span class="hljs-number">8096</span> <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  -v /tank/docker/jellyfin_config:/config <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  -v /tank/media:/media <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  --device=/dev/dri:/dev/dri <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  --restart=unless-stopped <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  jellyfin/jellyfin<br></code></pre></td></tr></tbody></table></figure><p>下表对这条命令的关键参数进行了解析：</p><table><thead><tr><th>标志</th><th>参数</th><th>描述</th></tr></thead><tbody><tr><td>docker run -d</td><td>-</td><td>以分离（后台）模式运行容器。</td></tr><tr><td>–name jellyfin</td><td>-</td><td>为容器指定一个易于管理的名称。</td></tr><tr><td>-p 8096:8096</td><td>-</td><td>将主机的8096端口映射到容器的8096端口，这是Jellyfin的默认Web端口。</td></tr><tr><td>-v…:/config</td><td>/tank/docker/jellyfin_config:/config</td><td><strong>数据持久化</strong>。将ZFS上的配置目录映射到容器内部，确保Jellyfin的设置和数据库在容器重启或重建后依然存在。</td></tr><tr><td>-v…:/media</td><td>/tank/media:/media</td><td>将ZFS上的媒体库目录映射到容器内部，让Jellyfin能够扫描和索引您的电影、剧集。</td></tr><tr><td>–device=/dev/dri:/dev/dri</td><td>-</td><td><strong>硬件加速核心</strong>。将主机的DRI（直接渲染基础架构）设备传递给容器，这使得Jellyfin能够调用AMD GPU的VCN（Video Core Next）硬件单元进行视频的硬件解码和编码。</td></tr><tr><td>–restart=unless-stopped</td><td>-</td><td>确保容器在服务器启动或意外崩溃后自动重启，除非被手动停止。</td></tr><tr><td>jellyfin/jellyfin</td><td>-</td><td>指定要使用的官方Jellyfin Docker镜像。</td></tr></tbody></table><p>导出到 Google 表格</p><h3 id="第三步：初始化Jellyfin"><a href="#第三步：初始化Jellyfin" class="headerlink" title="第三步：初始化Jellyfin"></a>第三步：初始化Jellyfin</h3><p>容器启动后，在浏览器中访问<code>http://&lt;your_server_ip&gt;:8096</code>，跟随设置向导完成初始化。在添加媒体库时，请选择容器内部的路径，例如<code>/media/movies</code>和<code>/media/tvshows</code>。</p><hr><h2 id="第六部分：虚拟化平台-—-KVM与Cockpit"><a href="#第六部分：虚拟化平台-—-KVM与Cockpit" class="headerlink" title="第六部分：虚拟化平台 — KVM与Cockpit"></a>第六部分：虚拟化平台 — KVM与Cockpit</h2><p>KVM (Kernel-based Virtual Machine) 是内建于Linux内核的原生虚拟化解决方案，性能卓越。Cockpit则是一个现代化的网页版服务器管理工具，通过其<code>cockpit-machines</code>插件，可以非常方便地图形化创建和管理KVM虚拟机。</p><h3 id="第一步：安装KVM及相关套件"><a href="#第一步：安装KVM及相关套件" class="headerlink" title="第一步：安装KVM及相关套件"></a>第一步：安装KVM及相关套件</h3><p>执行以下命令安装KVM、libvirt守护进程、virt-manager（一个桌面端的虚拟机管理器，可选）以及桥接网络工具 。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> apt install -y qemu-kvm libvirt-daemon-system virt-manager bridge-utils<br></code></pre></td></tr></tbody></table></figure><h3 id="第二步：安装Cockpit-Web控制台"><a href="#第二步：安装Cockpit-Web控制台" class="headerlink" title="第二步：安装Cockpit Web控制台"></a>第二步：安装Cockpit Web控制台</h3><p>安装Cockpit及其虚拟机管理插件。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> apt install -y cockpit cockpit-machines<br></code></pre></td></tr></tbody></table></figure><h3 id="第三步：配置虚拟网络与用户权限"><a href="#第三步：配置虚拟网络与用户权限" class="headerlink" title="第三步：配置虚拟网络与用户权限"></a>第三步：配置虚拟网络与用户权限</h3><p><strong>启动默认虚拟网络</strong>: KVM默认会创建一个名为<code>default</code>的NAT网络，对于多数场景已经足够。我们需确保它已启动并设置为开机自启。</p><figure class="highlight dos"><table><tbody><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><code class="hljs dos">sudo virsh <span class="hljs-built_in">net</span>-<span class="hljs-built_in">start</span> default<br>sudo virsh <span class="hljs-built_in">net</span>-autostart default<br>sudo virsh <span class="hljs-built_in">net</span>-list --all<br></code></pre></td></tr></tbody></table></figure><p><strong>添加用户到权限组</strong>: 这是一个脚本中遗漏但至关重要的步骤。将您的管理用户加入<code>libvirt</code>和<code>kvm</code>用户组，这样您就可以通过Cockpit或<code>virt-manager</code>管理虚拟机，而无需为每个操作都输入密码 。</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">sudo</span> usermod -aG libvirt,kvm <span class="hljs-variable">$LOGNAME</span><br></code></pre></td></tr></tbody></table></figure><ol><li>同样，您可能需要重新登录SSH会话或使用<code>newgrp</code>来使此变更生效。</li></ol><h3 id="第四步：访问Cockpit界面"><a href="#第四步：访问Cockpit界面" class="headerlink" title="第四步：访问Cockpit界面"></a>第四步：访问Cockpit界面</h3><p>在浏览器中打开<code>http://&lt;your_server_ip&gt;:9090</code>，使用您的服务器用户名（<code>spoto</code>）和密码登录。在左侧导航栏找到“Virtual Machines”选项卡，即可开始您的虚拟机创建之旅。</p><hr><h2 id="第七部分：AI释放-—-Ollama与ROCm加速"><a href="#第七部分：AI释放-—-Ollama与ROCm加速" class="headerlink" title="第七部分：AI释放 — Ollama与ROCm加速"></a>第七部分：AI释放 — Ollama与ROCm加速</h2><p>Ollama是一个极简的工具，它让在本地运行开源大语言模型（LLM）变得前所未有的简单。我们的目标是配置其Docker容器，使其能够充分利用AMD GPU的ROCm计算能力，实现高速推理。</p><h3 id="第一步：部署支持ROCm的Ollama容器"><a href="#第一步：部署支持ROCm的Ollama容器" class="headerlink" title="第一步：部署支持ROCm的Ollama容器"></a>第一步：部署支持ROCm的Ollama容器</h3><p>部署Ollama的关键在于将正确的GPU设备映射到容器内部。与Jellyfin不同，AI计算需要访问GPU的通用计算单元，而不仅仅是视频处理单元。</p><ul><li><code>--device=/dev/dri</code>：这个设备主要负责图形和视频相关的渲染任务，Jellyfin使用它进行硬件转码。</li><li><code>--device=/dev/kfd</code>：<code>kfd</code> (Kernel Fusion Driver) 是ROCm用于HSA异构计算的设备接口，是AI计算负载调度和执行的核心。</li></ul><p>因此，为了让Ollama正常工作，我们需要同时传递这两个设备 。</p><p>执行以下命令部署Ollama：</p><figure class="highlight apache"><table><tbody><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><code class="hljs apache"><span class="hljs-attribute">docker</span> run -d <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  --device=/dev/kfd <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  --device=/dev/dri <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  -v ollama:/root/.ollama <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  -p <span class="hljs-number">11434</span>:<span class="hljs-number">11434</span> <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  --name ollama <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  --restart=unless-stopped <span class="hljs-punctuation">\</span><br><span class="hljs-punctuation"></span>  ollama/ollama:rocm<br></code></pre></td></tr></tbody></table></figure><p>下表解析了这条命令的核心参数：</p><table><thead><tr><th>标志</th><th>参数</th><th>描述</th></tr></thead><tbody><tr><td>docker run -d</td><td>-</td><td>以分离（后台）模式运行容器。</td></tr><tr><td>–device=/dev/kfd</td><td>-</td><td><strong>计算核心</strong>。传递内核融合驱动设备，这是ROCm进行AI/HPC工作负载所必需的。</td></tr><tr><td>–device=/dev/dri</td><td>-</td><td>传递直接渲染架构设备，确保全面的图形/视频兼容性，部分模型可能需要。</td></tr><tr><td>-v ollama:/root/.ollama</td><td>-</td><td>创建一个名为ollama的Docker托管卷，用于持久化存储下载的大模型文件。</td></tr><tr><td>-p 11434:11434</td><td>-</td><td>映射Ollama的默认API端口到主机。</td></tr><tr><td>–name ollama</td><td>-</td><td>为容器指定一个易于管理的名称。</td></tr><tr><td>ollama/ollama:rocm</td><td>-</td><td><strong>至关重要</strong>。明确指定使用带有:rocm标签的镜像，该镜像内置了ROCm所需的库，而非标准的CPU版本镜像。</td></tr></tbody></table><p>导出到 Google 表格</p><h3 id="第二步：运行大语言模型"><a href="#第二步：运行大语言模型" class="headerlink" title="第二步：运行大语言模型"></a>第二步：运行大语言模型</h3><p>使用<code>docker exec</code>命令进入正在运行的Ollama容器，并执行<code>ollama</code>命令来下载并运行一个模型。这里以<code>gemma2:9b</code>为例，这是一个性能和尺寸均衡的优秀模型。</p><figure class="highlight applescript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs applescript">docker exec -<span class="hljs-keyword">it</span> ollama ollama <span class="hljs-built_in">run</span> gemma2:<span class="hljs-number">9</span>b<br></code></pre></td></tr></tbody></table></figure><p>Ollama会自动下载模型文件，首次运行需要一些时间。下载完成后，您会看到一个提示符，可以开始与模型进行对话。</p><h3 id="第三步：实时验证GPU加速"><a href="#第三步：实时验证GPU加速" class="headerlink" title="第三步：实时验证GPU加速"></a>第三步：实时验证GPU加速</h3><p>为了亲眼见证GPU加速的效果，请打开<strong>第二个</strong>到服务器的SSH连接。在第一个终端中与模型交互的同时，在第二个终端中运行以下命令：</p><figure class="highlight ebnf"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">watch rocm-smi</span><br></code></pre></td></tr></tbody></table></figure><p><code>watch</code>命令会每隔2秒刷新一次<code>rocm-smi</code>的输出。您将清晰地观察到：</p><ul><li>当模型加载时，其中一张GPU的<strong>VRAM（显存）占用率</strong>会急剧上升，因为整个模型被加载到了显存中。</li><li>当您输入问题，模型开始生成回答时，该GPU的**GPU Use%（利用率）<strong>和</strong>Pwr（功耗）**会显著飙升。</li></ul><p>这个现象无可辩驳地证明了，从硬件、ROCm驱动、Docker容器到Ollama应用的整个技术栈已经完美打通，您的AI推理服务器正在全速运行！</p><hr><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><h3 id="使命达成"><a href="#使命达成" class="headerlink" title="使命达成"></a>使命达成</h3><p>至此，这台二手服务器已经脱胎换骨。从一堆高性价比的硬件，我们构建了一台功能全面、性能强大的现代化服务器。它现在是：</p><ul><li>一个由ZFS守护的、数据安全可靠的<strong>网络附加存储（NAS）</strong>。</li><li>一个通过Samba协议，为全家设备提供服务的<strong>文件共享中心</strong>。</li><li>一个具备硬件转码能力的、强大的<strong>Jellyfin媒体服务器</strong>。</li><li>一个可以随时创建和销毁测试环境的<strong>KVM虚拟化平台</strong>。</li><li>一台利用多GPU并行计算，7x24小时待命的<strong>本地AI推理服务器</strong>。</li></ul><h3 id="Homelab的旅程"><a href="#Homelab的旅程" class="headerlink" title="Homelab的旅程"></a>Homelab的旅程</h3><p>将硬件组装起来只是第一步，真正的乐趣在于通过软件配置，赋予这台机器灵魂。这个从零开始的完整部署过程，充满了挑战，但也充满了探索和学习的乐趣。希望这份详尽的教程，能为您在打造自己的家庭实验室（Homelab）之路上，提供坚实的帮助和启发。</p><p>鼓励您在此基础上继续探索，部署更多有趣的应用容器，或者在KVM中尝试不同的操作系统。您的家庭数据与计算中心，拥有无限可能。</p><p>原文链接：<a href="https://gitee.com/spoto/UbuntuServer">Ubuntu-Server系统部署: 本教程旨在提供一份从零开始的、详尽的服务器部署指南。我们将以一个纯净的Ubuntu Server系统为起点，逐步将其打造成一台功能强大、性能卓越的多功能家庭服务器。</a>)</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;从零到英雄：打造你的终极AI、NAS与虚拟化母舰&quot;&gt;&lt;a href=&quot;#从零到英雄：打造你的终极AI、NAS与虚拟化母舰&quot; class=&quot;headerlink&quot; title=&quot;从零到英雄：打造你的终极AI、NAS与虚拟化母舰&quot;&gt;&lt;/a&gt;从零到英雄：打造你的终极AI</summary>
      
    
    
    
    
    <category term="AI" scheme="https://www.qxz5637.top/tags/AI/"/>
    
    <category term="NAS" scheme="https://www.qxz5637.top/tags/NAS/"/>
    
  </entry>
  
  <entry>
    <title>Python 虚拟环境操作</title>
    <link href="https://www.qxz5637.top/2025/06/25/Python%20%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%E6%93%8D%E4%BD%9C/"/>
    <id>https://www.qxz5637.top/2025/06/25/Python%20%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%E6%93%8D%E4%BD%9C/</id>
    <published>2025-06-25T01:02:23.584Z</published>
    <updated>2025-06-25T01:11:28.575Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Python-虚拟环境操作"><a href="#Python-虚拟环境操作" class="headerlink" title="Python 虚拟环境操作"></a>Python 虚拟环境操作</h1><p>在 Python 编程里，虚拟环境是极为实用的工具。它能够为不同项目创建相互隔离的环境，避免包版本冲突的问题。下面为你介绍在不同操作系统上创建、激活和退出虚拟环境的方法。</p><h3 id="1-运用-venv-模块创建虚拟环境（适用于-Python-3-3-及更高版本）"><a href="#1-运用-venv-模块创建虚拟环境（适用于-Python-3-3-及更高版本）" class="headerlink" title="1. 运用 venv 模块创建虚拟环境（适用于 Python 3.3 及更高版本）"></a>1. 运用 venv 模块创建虚拟环境（适用于 Python 3.3 及更高版本）</h3><p>Windows 系统</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">python -m venv myenv<br></code></pre></td></tr></tbody></table></figure><p>macOS/Linux 系统</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">python3 -m venv myenv<br></code></pre></td></tr></tbody></table></figure><p>这里的myenv是虚拟环境的名称，你可以根据实际情况进行修改。</p><h3 id="2-激活虚拟环境"><a href="#2-激活虚拟环境" class="headerlink" title="2.激活虚拟环境"></a>2.激活虚拟环境</h3><p>Windows 系统</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">myenv\Scripts\activate<br></code></pre></td></tr></tbody></table></figure><p>macOS/Linux 系统</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">source</span> myenv/bin/activate<br></code></pre></td></tr></tbody></table></figure><p>当虚拟环境成功激活后，命令提示符前会显示环境名称，以此作为标识。</p><h3 id="3-退出虚拟环境"><a href="#3-退出虚拟环境" class="headerlink" title="3. 退出虚拟环境"></a>3. 退出虚拟环境</h3><p>无论使用的是 Windows、macOS 还是 Linux 系统，退出虚拟环境的命令都是一样的：</p><figure class="highlight bash"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">deactivate<br></code></pre></td></tr></tbody></table></figure><h3 id="4-使用-pip-管理包"><a href="#4-使用-pip-管理包" class="headerlink" title="4. 使用 pip 管理包"></a>4. 使用 pip 管理包</h3><p>在虚拟环境激活的状态下，你可以像平常一样使用 pip 来安装、升级或卸载包。例如：</p><figure class="highlight bash"><table><tbody><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><code class="hljs bash">pip install package_name<br>pip uninstall package_name<br>pip list<br></code></pre></td></tr></tbody></table></figure><h3 id="5-其他注意要点"><a href="#5-其他注意要点" class="headerlink" title="5. 其他注意要点"></a>5. 其他注意要点</h3><p>指定 Python 版本：要是系统中同时安装了 Python 2 和 Python 3，你可以使用python3来明确指定使用 Python 3。<br>删除虚拟环境：如果想要删除虚拟环境，只需把对应的文件夹删除即可。不过要记得先退出该虚拟环境。<br>第三方工具：除了 venv 模块，你还可以使用virtualenv或者conda来创建虚拟环境，它们都有各自的特点和适用场景。</p><p>按照上述步骤操作，你就能轻松管理 Python 虚拟环境了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Python-虚拟环境操作&quot;&gt;&lt;a href=&quot;#Python-虚拟环境操作&quot; class=&quot;headerlink&quot; title=&quot;Python 虚拟环境操作&quot;&gt;&lt;/a&gt;Python 虚拟环境操作&lt;/h1&gt;&lt;p&gt;在 Python 编程里，虚拟环境是极为实用的工具。</summary>
      
    
    
    
    <category term="Python" scheme="https://www.qxz5637.top/categories/Python/"/>
    
    
  </entry>
  
  <entry>
    <title>Windows Server 2025 正式发布</title>
    <link href="https://www.qxz5637.top/2025/06/19/Windows%20Server%202025%20%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/"/>
    <id>https://www.qxz5637.top/2025/06/19/Windows%20Server%202025%20%E6%AD%A3%E5%BC%8F%E5%8F%91%E5%B8%83/</id>
    <published>2025-06-19T12:46:00.969Z</published>
    <updated>2025-06-19T12:46:03.826Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Windows-Server-2025-正式发布！低配电脑也能轻松驾驭，无广告更纯净！-免费下载-激活"><a href="#Windows-Server-2025-正式发布！低配电脑也能轻松驾驭，无广告更纯净！-免费下载-激活" class="headerlink" title="Windows Server 2025 正式发布！低配电脑也能轻松驾驭，无广告更纯净！ 免费下载+激活"></a>Windows Server 2025 正式发布！低配电脑也能轻松驾驭，无广告更纯净！ 免费下载+激活</h1><p>近日，微软正式发布了全新的服务器操作系统——<strong>Windows Server 2025</strong>。相比以往的服务器系统，这一代带来了不少令人眼前一亮的变化。不仅性能强大，而且对硬件的要求极其友好，<strong>就算是老旧低配电脑也能流畅运行</strong>！</p><p><img src="https://img.qxz5637.top/images/picgo/2025/06/11/20250611063553672.webp" alt="图片[1]-Windows Server 2025 正式发布！低配电脑也能轻松驾驭，无广告更纯净！ 免费下载+激活-零度博客"></p><h2 id="为什么推荐-Windows-Server-2025？"><a href="#为什么推荐-Windows-Server-2025？" class="headerlink" title="为什么推荐 Windows Server 2025？"></a>为什么推荐 Windows Server 2025？</h2><h3 id="✅-无需高配，低端机一样跑得动"><a href="#✅-无需高配，低端机一样跑得动" class="headerlink" title="✅ 无需高配，低端机一样跑得动"></a>✅ 无需高配，低端机一样跑得动</h3><p>很多人一听到“Server”系统就觉得门槛很高，担心安装复杂、资源占用大。但实际上，Windows Server 2025 相当“轻量”，对 CPU、内存和硬盘的要求都比 Windows 11 更低。在测试中，<strong>一些仅有 4GB 内存的旧笔记本都能顺畅运行</strong>。</p><h3 id="✅-没有广告，极其纯净"><a href="#✅-没有广告，极其纯净" class="headerlink" title="✅ 没有广告，极其纯净"></a>✅ 没有广告，极其纯净</h3><p>与近几年 Windows 10 和 Windows 11 越来越“商业化”的风格不同，Windows Server 2025 完全<strong>没有内置广告、推荐内容、强制推送软件</strong>等恼人的东西。系统非常纯净，开机就能直接进入桌面，不会被一堆弹窗打扰。</p><h3 id="✅-比-Windows-11-Pro-更好用？"><a href="#✅-比-Windows-11-Pro-更好用？" class="headerlink" title="✅ 比 Windows 11 Pro 更好用？"></a>✅ 比 Windows 11 Pro 更好用？</h3><p>Windows 11 Pro 虽然是专业版，但在 UI 简洁性、资源占用、后台服务数量等方面，依然不如 Server 系统来的纯粹。<strong>很多高级用户和极客玩家，更喜欢用 Server 系统来作为主力桌面</strong>，就是因为它省资源、不打扰、足够稳定。</p><h3 id="✅-安装激活超简单"><a href="#✅-安装激活超简单" class="headerlink" title="✅ 安装激活超简单"></a>✅ 安装激活超简单</h3><p>别被“Server”两个字吓到，其实<strong>Windows Server 2025 的安装过程与普通 Windows 几乎一样</strong>，甚至更快、更干净。配合现成的激活工具或者正版密钥，几分钟就能搞定部署。</p><p>Windows server 2025 官方下载【<strong><a href="https://www.freedidi.com/?golink=aHR0cHM6Ly93d3cubWljcm9zb2Z0LmNvbS96aC1jbi9ldmFsY2VudGVyL2Rvd25sb2FkLXdpbmRvd3Mtc2VydmVyLTIwMjU=">简体中文版</a></strong>】、【<a href="https://www.freedidi.com/?golink=aHR0cHM6Ly93d3cubWljcm9zb2Z0LmNvbS96aC10dy9ldmFsY2VudGVyL2Rvd25sb2FkLXdpbmRvd3Mtc2VydmVyLTIwMjU="><strong>繁体中文版</strong></a>】</p><p>Windows server 2025 转换到正式版的命令：</p><figure class="highlight jboss-cli"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs jboss-cli">DISM <span class="hljs-string">/online</span> <span class="hljs-string">/Set-Edition</span><span class="hljs-function">:ServerDatacenter</span> <span class="hljs-string">/ProductKey</span><span class="hljs-function">:D764K-2NDRG-47T6Q-P8T8W-YP6DF</span> <span class="hljs-string">/AcceptEula</span><br></code></pre></td></tr></tbody></table></figure><p>微软官方提供的KMS激活密钥 【<a href="https://www.freedidi.com/?golink=aHR0cHM6Ly9sZWFybi5taWNyb3NvZnQuY29tL3poLWNuL3dpbmRvd3Mtc2VydmVyL2dldC1zdGFydGVkL2ttcy1jbGllbnQtYWN0aXZhdGlvbi1rZXlzP3RhYnM9c2VydmVyMjAyNSUyQ3dpbmRvd3MxMTEwbHRzYyUyQ3ZlcnNpb24xODAzJTJDd2luZG93czgx">点击查看</a> 】</p><p><strong>KMS 以管理员身份运行终端，执行命令：</strong></p><figure class="highlight apache"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">slmgr</span> -ipk D764K-<span class="hljs-number">2</span>NDRG-<span class="hljs-number">47</span>T6Q-P8T8W-YP6DF<br><br><span class="hljs-attribute">slmgr</span> -skms kms.<span class="hljs-number">0</span>t.net.cn<br><br><span class="hljs-attribute">slmgr</span> -ato<br></code></pre></td></tr></tbody></table></figure><hr><h2 id="适合哪些人使用？"><a href="#适合哪些人使用？" class="headerlink" title="适合哪些人使用？"></a>适合哪些人使用？</h2><ul><li>想给老电脑重生的用户</li><li>追求无广告、极致干净系统的用户</li><li>技术人员、自媒体、开发者</li><li>需要长期运行服务（如网站、应用、脚本）的极客</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Windows-Server-2025-正式发布！低配电脑也能轻松驾驭，无广告更纯净！-免费下载-激活&quot;&gt;&lt;a href=&quot;#Windows-Server-2025-正式发布！低配电脑也能轻松驾驭，无广告更纯净！-免费下载-激活&quot; class=&quot;headerlin</summary>
      
    
    
    
    <category term="系统" scheme="https://www.qxz5637.top/categories/%E7%B3%BB%E7%BB%9F/"/>
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>Flask项目实战之1.项目搭建</title>
    <link href="https://www.qxz5637.top/2025/06/01/Flask%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98%E4%B9%8B1.%E9%A1%B9%E7%9B%AE%E6%90%AD%E5%BB%BA/"/>
    <id>https://www.qxz5637.top/2025/06/01/Flask%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98%E4%B9%8B1.%E9%A1%B9%E7%9B%AE%E6%90%AD%E5%BB%BA/</id>
    <published>2025-06-01T00:19:12.339Z</published>
    <updated>2025-06-01T00:19:13.149Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Flask项目实战之一-项目搭建"><a href="#Flask项目实战之一-项目搭建" class="headerlink" title="Flask项目实战之一.项目搭建"></a>Flask项目实战之一.项目搭建</h1><p>文章目录</p><ul><li>一、项目目录创建</li><li>二、CMS模型定义和用户添加<ul><li>1.CMS管理员用户模型定义</li><li>2.添加用户</li></ul></li><li>三、CMS登录页面搭建</li></ul><p>那些常见网页中的彩蛋，你都知道吗？</p><blockquote><p>百度、知乎、B站你可能经常会用到，但是你知道隐藏在其中的彩蛋吗？Google、Firefox，你可能也会经常使用，但是你发现了它们的彩蛋吗？我们一起来看看吧(<em>_</em>)？  百度的一个彩蛋还可以教你想心仪的小姐姐表白呢O(∩_∩)O</p></blockquote><p>Falsk项目实战是做一个简单的论坛平台，实现基本功能。</p><p>Github和Gitee代码<strong>同步更新</strong>：</p><p><a href="https://cloud.tencent.com/developer/tools/blog-entry?target=https://github.com/PythonFullStack/Flask_BBS&amp;objectId=1667396&amp;objectType=1&amp;isNewArticle=undefined">https://github.com/PythonFullStack/Flask_BBS</a>；</p><p><a href="https://cloud.tencent.com/developer/tools/blog-entry?target=https://gitee.com/Python_Full_Stack/Flask_BBS&amp;objectId=1667396&amp;objectType=1&amp;isNewArticle=undefined">https://gitee.com/Python_Full_Stack/Flask_BBS</a>。</p><h2 id="一、项目目录创建"><a href="#一、项目目录创建" class="headerlink" title="一、项目目录创建"></a>一、项目目录创建</h2><p>在真实项目中，实现前台front和后台cms<strong>分离实现</strong>，以优化整个项目的代码结构。  整个项目默认使用PyCHarm进行开发。</p><p>创建用户目录<strong>Flask_BBS</strong>，该项目所有的文件均保存在该目录中。</p><p>先创建<strong>程序主入口文件</strong>bbs.py如下：</p><figure class="highlight javascript"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> <span class="hljs-title class_">Flask</span><br><span class="hljs-keyword">from</span> exts <span class="hljs-keyword">import</span> db<br><span class="hljs-keyword">from</span> apps.<span class="hljs-property">cms</span>.<span class="hljs-property">views</span> <span class="hljs-keyword">import</span> cms_bp<br><span class="hljs-keyword">from</span> apps.<span class="hljs-property">front</span>.<span class="hljs-property">views</span> <span class="hljs-keyword">import</span> front_bp<br><span class="hljs-keyword">import</span> configapp = <span class="hljs-title class_">Flask</span>(__name__)<br>app.<span class="hljs-property">config</span>.<span class="hljs-title function_">from_object</span>(config)<br>db.<span class="hljs-title function_">init_app</span>(app)app.<span class="hljs-title function_">register_blueprint</span>(cms_bp)<br>app.<span class="hljs-title function_">register_blueprint</span>(front_bp)<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>app.<span class="hljs-title function_">run</span>(debug=<span class="hljs-title class_">True</span>)<br></code></pre></td></tr></tbody></table></figure><p>再创建<strong>静态资源文件</strong>保存目录static和<strong>模板</strong>保存目录templates。</p><p>再创建<strong>配置文件</strong>config.py如下：</p><h1 id="数据库连接配置"><a href="#数据库连接配置" class="headerlink" title="数据库连接配置"></a>数据库连接配置</h1><figure class="highlight javascript"><table><tbody><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><code class="hljs javascript"><span class="hljs-variable constant_">HOSTNAME</span> = <span class="hljs-string">'127.0.0.1'</span><br><span class="hljs-variable constant_">PORT</span> = <span class="hljs-number">3306</span><br><span class="hljs-variable constant_">USERNAME</span> = <span class="hljs-string">'root'</span><br><span class="hljs-variable constant_">PASSWORD</span> = <span class="hljs-string">'root'</span><br><span class="hljs-variable constant_">DATABASE</span> = <span class="hljs-string">'flask_bbs'</span><br><span class="hljs-variable constant_">DB_URL</span> = <span class="hljs-string">'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'</span>.<span class="hljs-title function_">format</span>(<span class="hljs-variable constant_">USERNAME</span>, <span class="hljs-variable constant_">PASSWORD</span>, <span class="hljs-variable constant_">HOSTNAME</span>, <span class="hljs-variable constant_">PORT</span>, <span class="hljs-variable constant_">DATABASE</span>)<span class="hljs-variable constant_">SQLALCHEMY_DATABASE_URI</span> = <span class="hljs-variable constant_">DB_URL</span><br><span class="hljs-variable constant_">SQLALCHEMY_TRACK_MODIFICATIONS</span> = <span class="hljs-title class_">False</span><br></code></pre></td></tr></tbody></table></figure><p>再创建<strong>中间文件</strong>exts.py如下：</p><figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">from</span> flask_sqlalchemy<br><span class="hljs-keyword">import</span> <span class="hljs-title class_">SQLAlchemydb</span> = <span class="hljs-title class_">SQLAlchemy</span>()<br></code></pre></td></tr></tbody></table></figure><p>再创建<a href="https://cloud.tencent.com/product/tencentdb-catalog?from_column=20065&amp;from=20065"><strong>数据库</strong></a><strong>映射迁移管理文件</strong>manage.py如下：</p><figure class="highlight javascript"><table><tbody><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><code class="hljs javascript"><span class="hljs-keyword">from</span> flask_script <span class="hljs-keyword">import</span> <span class="hljs-title class_">Manager</span><br><span class="hljs-keyword">from</span> bbs <span class="hljs-keyword">import</span> app<br><span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> <span class="hljs-title class_">Migrate</span>, <span class="hljs-title class_">MigrateCommand</span><br><span class="hljs-keyword">from</span> exts <span class="hljs-keyword">import</span> dbmanager = <span class="hljs-title class_">Manager</span>(app)<br><span class="hljs-title class_">Migrate</span>(app, db)manager.<span class="hljs-title function_">add_command</span>(<span class="hljs-string">'db'</span>, <span class="hljs-title class_">MigrateCommand</span>)<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>manager.<span class="hljs-title function_">run</span>()<br></code></pre></td></tr></tbody></table></figure><p>在项目目录右键新建<strong>Python</strong>** Package<strong>为</strong>apps**，下面新建Python包cms、front和common用于保存<strong>后台</strong>、<strong>前台</strong>和<strong>公有文件</strong>。</p><p>在cms和front目录下均创建<strong>表单文件</strong>forms.py、<strong>模型文件</strong>models.py和<strong>视图文件</strong>views.py文件。</p><p>cms目录下的views.py如下：</p><figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript">cms_bp = <span class="hljs-title class_">Blueprint</span>(<span class="hljs-string">'cms'</span>, __name__, url_prefix=<span class="hljs-string">'/cms'</span>)@cms_bp.<span class="hljs-title function_">route</span>(<span class="hljs-string">'/'</span>)<br>def <span class="hljs-title function_">index</span>():<br></code></pre></td></tr></tbody></table></figure><p>return ‘后台管理首页’<br>front目录下的views.py如下：</p><figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> <span class="hljs-title class_">Blueprintfront</span>_bp = <span class="hljs-title class_">Blueprint</span>(<span class="hljs-string">'front'</span>, __name__)@front_bp.<span class="hljs-title function_">route</span>(<span class="hljs-string">'/'</span>)<br>def <span class="hljs-title function_">index</span>():<br></code></pre></td></tr></tbody></table></figure><p>return ‘前台首页’<br>运行主程序后，显示：</p><p><img src="https://img.qxz5637.top/images/qexo/2025/06/01/68abbf39c291c2a2381e6db756b083f3.gif"></p><p>如果出现类似的效果，则项目目录基本构建完成。</p><h2 id="二、CMS模型定义和用户添加"><a href="#二、CMS模型定义和用户添加" class="headerlink" title="二、CMS模型定义和用户添加"></a>二、CMS模型定义和用户添加</h2><h3 id="1-CMS管理员用户模型定义"><a href="#1-CMS管理员用户模型定义" class="headerlink" title="1.CMS管理员用户模型定义"></a>1.CMS管理员用户模型定义</h3><p>cms目录下的models.py如下：</p><figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">from</span> exts <span class="hljs-keyword">import</span> db<br><span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime<span class="hljs-keyword">class</span> <span class="hljs-title class_">CMSUser</span>(db.<span class="hljs-property">Model</span>):<br></code></pre></td></tr></tbody></table></figure><p>‘’’后台管理员用户类’’’<br>__</p><figure class="highlight javascript"><table><tbody><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><code class="hljs javascript">tablename__ = <span class="hljs-string">'cms_user'</span><br>id = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-property">Integer</span>, primary_key=<span class="hljs-title class_">True</span>, autoincrement=<span class="hljs-title class_">True</span>)<br>username = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-title class_">String</span>(<span class="hljs-number">30</span>), nullable=<span class="hljs-title class_">False</span>)<br>password = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-title class_">String</span>(<span class="hljs-number">30</span>), nullable=<span class="hljs-title class_">False</span>)<br>email = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-title class_">String</span>(<span class="hljs-number">50</span>), nullable=<span class="hljs-title class_">False</span>, unique=<span class="hljs-title class_">True</span>)<br>join_time = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-property">DateTime</span>, <span class="hljs-keyword">default</span>=datetime.<span class="hljs-title function_">now</span>())<br></code></pre></td></tr></tbody></table></figure><p>创建了CMSUser后台管理员用户类。</p><p>在manage.py中导入模型：</p><figure class="highlight javascript"><table><tbody><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><code class="hljs javascript">javascriptfrom flask_script <span class="hljs-keyword">import</span> <span class="hljs-title class_">Manager</span><br><span class="hljs-keyword">from</span> bbs <span class="hljs-keyword">import</span> app<br><span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> <span class="hljs-title class_">Migrate</span>, <span class="hljs-title class_">MigrateCommand</span><br><span class="hljs-keyword">from</span> exts <span class="hljs-keyword">import</span> db<br><span class="hljs-keyword">from</span> apps.<span class="hljs-property">cms</span>.<span class="hljs-property">models</span> <span class="hljs-keyword">import</span> <span class="hljs-title class_">CMSUsermanager</span> = <span class="hljs-title class_">Manager</span>(app)<br><span class="hljs-title class_">Migrate</span>(app, db)manager.<span class="hljs-title function_">add_command</span>(<span class="hljs-string">'db'</span>, <span class="hljs-title class_">MigrateCommand</span>)<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>manager.<span class="hljs-title function_">run</span>()<br></code></pre></td></tr></tbody></table></figure><p>此时在命令行的当前目录下依次执行<code>python manage.py db init</code>、<code>python manage.py db migrate</code>、<code>python manage.py db upgrade</code>，执行成功后可以在数据库flask_bbs中看到cms_user表。</p><h3 id="2-添加用户"><a href="#2-添加用户" class="headerlink" title="2.添加用户"></a>2.添加用户</h3><p>在manage.py中添加代码来实现<strong>通过命令行添加用户</strong>：</p><figure class="highlight javascript"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">from</span> flask_script <span class="hljs-keyword">import</span> <span class="hljs-title class_">Manager</span><br><span class="hljs-keyword">from</span> bbs <span class="hljs-keyword">import</span> app<br><span class="hljs-keyword">from</span> flask_migrate <span class="hljs-keyword">import</span> <span class="hljs-title class_">Migrate</span>, <span class="hljs-title class_">MigrateCommand</span><br><span class="hljs-keyword">from</span> exts <span class="hljs-keyword">import</span> db<br><span class="hljs-keyword">from</span> apps.<span class="hljs-property">cms</span>.<span class="hljs-property">models</span> <span class="hljs-keyword">import</span> <span class="hljs-title class_">CMSUser</span><br><br>manager = <span class="hljs-title class_">Manager</span>(app)<br><span class="hljs-title class_">Migrate</span>(app, db)<br><br>manager.<span class="hljs-title function_">add_command</span>(<span class="hljs-string">'db'</span>, <span class="hljs-title class_">MigrateCommand</span>)<br><br><br>@manager.<span class="hljs-title function_">option</span>(<span class="hljs-string">'-u'</span>, <span class="hljs-string">'--username'</span>, dest=<span class="hljs-string">'username'</span>)<br>@manager.<span class="hljs-title function_">option</span>(<span class="hljs-string">'-p'</span>, <span class="hljs-string">'--password'</span>, dest=<span class="hljs-string">'password'</span>)<br>@manager.<span class="hljs-title function_">option</span>(<span class="hljs-string">'-e'</span>, <span class="hljs-string">'--email'</span>, dest=<span class="hljs-string">'email'</span>)<br>def <span class="hljs-title function_">create_cms_user</span>(username, password, email):<br>    user = <span class="hljs-title class_">CMSUser</span>(username=username, password=password, email=email)<br>    db.<span class="hljs-property">session</span>.<span class="hljs-title function_">add</span>(user)<br>    db.<span class="hljs-property">session</span>.<span class="hljs-title function_">commit</span>()<br>    <span class="hljs-title function_">print</span>(<span class="hljs-string">'CMS用户添加成功'</span>)<br><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>    manager.<span class="hljs-title function_">run</span>()<br></code></pre></td></tr></tbody></table></figure><p>此时在命令行中执行<code>python manage.py create_cms_user -u Corley -p admin -e 123@163.com</code>，打印<code>CMS用户添加成功</code>，此时查询数据库表cms_user：</p><figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">select * <span class="hljs-keyword">from</span> cms_user;<br></code></pre></td></tr></tbody></table></figure><p>打印：</p><figure class="highlight javascript"><table><tbody><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><code class="hljs javascript">+----+----------+----------+-------------+---------------------+<br>| id | username | password | email       | join_time           |<br>+----+----------+----------+-------------+---------------------+<br>|  <span class="hljs-number">1</span> | <span class="hljs-title class_">Corley</span>   | admin    | <span class="hljs-number">123</span>@<span class="hljs-number">163.</span>com | <span class="hljs-number">2020</span>-<span class="hljs-number">05</span>-<span class="hljs-number">18</span> <span class="hljs-number">20</span>:<span class="hljs-number">26</span>:<span class="hljs-number">19</span> |<br>+----+----------+----------+-------------+---------------------+<br><span class="hljs-number">1</span> row <span class="hljs-keyword">in</span> <span class="hljs-title function_">set</span> (<span class="hljs-number">0.00</span> sec)<br></code></pre></td></tr></tbody></table></figure><p>显然，数据插入成功，但是密码是明文，存在安全隐患，可以进一步进行优化。</p><p>删除cms_user表中数据，重新定义模型models.py如下：</p><figure class="highlight javascript"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime<br><span class="hljs-keyword">from</span> werkzeug.<span class="hljs-property">security</span> <span class="hljs-keyword">import</span> generate_password_hash<br><span class="hljs-keyword">from</span> exts <span class="hljs-keyword">import</span> db<br><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">CMSUser</span>(db.<span class="hljs-property">Model</span>):<br>    <span class="hljs-string">''</span><span class="hljs-string">'后台管理员用户类'</span><span class="hljs-string">''</span><br>    __tablename__ = <span class="hljs-string">'cms_user'</span><br>    id = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-property">Integer</span>, primary_key=<span class="hljs-title class_">True</span>, autoincrement=<span class="hljs-title class_">True</span>)<br>    username = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-title class_">String</span>(<span class="hljs-number">30</span>), nullable=<span class="hljs-title class_">False</span>)<br>    _password = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-title class_">String</span>(<span class="hljs-number">100</span>), nullable=<span class="hljs-title class_">False</span>)<br>    email = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-title class_">String</span>(<span class="hljs-number">50</span>), nullable=<span class="hljs-title class_">False</span>, unique=<span class="hljs-title class_">True</span>)<br>    join_time = db.<span class="hljs-title class_">Column</span>(db.<span class="hljs-property">DateTime</span>, <span class="hljs-keyword">default</span>=datetime.<span class="hljs-title function_">now</span>())<br><br>    def <span class="hljs-title function_">__init__</span>(self, username, password, email):<br>        self.<span class="hljs-property">username</span> = username<br>        self.<span class="hljs-property">password</span> = password<br>        self.<span class="hljs-property">email</span> = email<br><br>    @property<br>    def <span class="hljs-title function_">password</span>(self):<br>        <span class="hljs-keyword">return</span> self.<span class="hljs-property">_password</span><br><br>    @password.<span class="hljs-property">setter</span><br>    def <span class="hljs-title function_">password</span>(self, raw_password):<br>        self.<span class="hljs-property">_password</span> = <span class="hljs-title function_">generate_password_hash</span>(raw_password)<br></code></pre></td></tr></tbody></table></figure><p>使用<code>generate_password_hash()</code>对密码进行hash加密。  此时再依次执行<code>python manage.py db migrate</code>、<code>python manage.py db upgrade</code>、<code>python manage.py create_cms_user -u Corley -p admin -e 123@163.com</code>，打印<code>CMS用户添加成功</code>，</p><p>再查询数据库表cms_user：</p><figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs javascript">select * <span class="hljs-keyword">from</span> cms_user;<br></code></pre></td></tr></tbody></table></figure><p>打印：</p><figure class="highlight javascript"><table><tbody><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><code class="hljs javascript">+----+----------+-------------+---------------------+------------------------------------------------------------------------------------------------+<br>| id | username | email       | join_time           | _password                                                                                      |<br>+----+----------+-------------+---------------------+------------------------------------------------------------------------------------------------+<br>|  <span class="hljs-number">2</span> | <span class="hljs-title class_">Corley</span>   | <span class="hljs-number">123</span>@<span class="hljs-number">163.</span>com | <span class="hljs-number">2020</span>-<span class="hljs-number">05</span>-<span class="hljs-number">18</span> <span class="hljs-number">20</span>:<span class="hljs-number">42</span>:<span class="hljs-number">05</span> | <span class="hljs-attr">pbkdf2</span>:<span class="hljs-attr">sha256</span>:<span class="hljs-number">150000</span>$OtgjW9d7$6e1109428317afb0b3c093e1eb87da34c74d0a232d5cb15272737e5d218fd421 |<br>+----+----------+-------------+---------------------+------------------------------------------------------------------------------------------------+<br><span class="hljs-number">1</span> row <span class="hljs-keyword">in</span> <span class="hljs-title function_">set</span> (<span class="hljs-number">0.00</span> sec)                                                                                                           <br></code></pre></td></tr></tbody></table></figure><p>显然，此时的密码是经过加密的数据。</p><h2 id="三、CMS登录页面搭建"><a href="#三、CMS登录页面搭建" class="headerlink" title="三、CMS登录页面搭建"></a>三、CMS登录页面搭建</h2><p>本项目的很多前端HTML页面和组件都是使用BootStrap中文网<a href="https://cloud.tencent.com/developer/tools/blog-entry?target=https://www.bootcss.com/&amp;objectId=1667396&amp;objectType=1&amp;isNewArticle=undefined">https://www.bootcss.com/</a>提供的模板。</p><p>cms目录下的views.py如下：</p><figure class="highlight javascript"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> <span class="hljs-title class_">Blueprint</span>, render_template, views<br><br>cms_bp = <span class="hljs-title class_">Blueprint</span>(<span class="hljs-string">'cms'</span>, __name__, url_prefix=<span class="hljs-string">'/cms'</span>)<br><br>@cms_bp.<span class="hljs-title function_">route</span>(<span class="hljs-string">'/'</span>)<br>def <span class="hljs-title function_">index</span>():<br>    <span class="hljs-keyword">return</span> <span class="hljs-string">'后台管理首页'</span><br><br><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">LoginView</span>(views.<span class="hljs-property">MethodView</span>):<br>    def <span class="hljs-title function_">get</span>(self):<br>        <span class="hljs-keyword">return</span> <span class="hljs-title function_">render_template</span>(<span class="hljs-string">'cms/cms_login.html'</span>)<br><br><br>cms_bp.<span class="hljs-title function_">add_url_rule</span>(<span class="hljs-string">'/login/'</span>, view_func=<span class="hljs-title class_">LoginView</span>.<span class="hljs-title function_">as_view</span>(<span class="hljs-string">'login'</span>))<br></code></pre></td></tr></tbody></table></figure><p>主程序文件bbs.py如下：</p><figure class="highlight javascript"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs javascript"><span class="hljs-string">''</span><span class="hljs-string">'</span><br><span class="hljs-string">前台 front</span><br><span class="hljs-string">后台 cms</span><br><span class="hljs-string">公有 common</span><br><span class="hljs-string">'</span><span class="hljs-string">''</span><br><br><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> <span class="hljs-title class_">Flask</span><br><span class="hljs-keyword">from</span> exts <span class="hljs-keyword">import</span> db<br><span class="hljs-keyword">from</span> apps.<span class="hljs-property">cms</span>.<span class="hljs-property">views</span> <span class="hljs-keyword">import</span> cms_bp<br><span class="hljs-keyword">from</span> apps.<span class="hljs-property">front</span>.<span class="hljs-property">views</span> <span class="hljs-keyword">import</span> front_bp<br><span class="hljs-keyword">import</span> config<br><br><br>app = <span class="hljs-title class_">Flask</span>(__name__)<br>app.<span class="hljs-property">config</span>.<span class="hljs-title function_">from_object</span>(config)<br>app.<span class="hljs-property">config</span>[<span class="hljs-string">'TEMPLATE_AUTO_RELOAD'</span>] = <span class="hljs-title class_">True</span><br>db.<span class="hljs-title function_">init_app</span>(app)<br><br>app.<span class="hljs-title function_">register_blueprint</span>(cms_bp)<br>app.<span class="hljs-title function_">register_blueprint</span>(front_bp)<br><br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:<br>    app.<span class="hljs-title function_">run</span>(debug=<span class="hljs-title class_">True</span>)<br></code></pre></td></tr></tbody></table></figure><p>templates目录下创建cms子目录，下面创建cms_login.html，使用<a href="https://cloud.tencent.com/developer/tools/blog-entry?target=https://v3.bootcss.com/examples/signin/&amp;objectId=1667396&amp;objectType=1&amp;isNewArticle=undefined">https://v3.bootcss.com/examples/signin/</a>源代码，并进行一定修改如下：</p><figure class="highlight javascript"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><code class="hljs javascript">&lt;!<span class="hljs-variable constant_">DOCTYPE</span> html&gt;<br>&lt;html lang="zh-CN"&gt;<br>&lt;head&gt;<br>    &lt;meta charset="utf-8"&gt;<br>    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;<br>    &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;<br>    &lt;!-- 上述3个meta标签*必须*放在最前面，任何其他内容都*必须*跟随其后！ --&gt;<br>    &lt;meta name="description" content=""&gt;<br>    &lt;meta name="author" content=""&gt;<br>    &lt;link rel="icon" href="{{ url_for('static', filename='cms/images/bbs-favicon.ico') }}"&gt;<br><br>    &lt;title&gt;CMS用户登录&lt;/title&gt;<br><br>    &lt;!-- Bootstrap core CSS --&gt;<br>    &lt;link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"&gt;<br><br>    &lt;!-- Custom styles for this template --&gt;<br>    &lt;link href="{{ url_for('static', filename='cms/css/signin.css') }}" rel="stylesheet"&gt;<br>    &lt;![endif]--&gt;<br>&lt;/head&gt;<br><br>&lt;body&gt;<br><br>&lt;div class="container"&gt;<br><br>    &lt;form class="form-signin" method="post"&gt;<br>        &lt;h2 class="form-signin-heading"&gt;请登录&lt;/h2&gt;<br>        &lt;label for="inputEmail" class="sr-only"&gt;邮箱地址&lt;/label&gt;<br>        &lt;input type="email" id="inputEmail" class="form-control" name="email" placeholder="邮箱地址" required autofocus&gt;<br>        &lt;label for="inputPassword" class="sr-only"&gt;密码&lt;/label&gt;<br>        &lt;input type="password" id="inputPassword" class="form-control" name="password" placeholder="密码" required&gt;<br>        &lt;div class="checkbox"&gt;<br>            &lt;label&gt;<br>                &lt;input type="checkbox" value="remember-me" name="remember"&gt; 记住我<br>            &lt;/label&gt;<br>        &lt;/div&gt;<br>        &lt;button class="btn btn-lg btn-primary btn-block" type="submit"&gt;立即登录&lt;/button&gt;<br>    &lt;/form&gt;<br><br>&lt;/div&gt; &lt;!-- /container --&gt;<br><br><br>&lt;/body&gt;<br>&lt;/html&gt;<br></code></pre></td></tr></tbody></table></figure><p>static目录下创建cms子目录，下面创建<strong>css</strong>目录和images目录，css目录下创建signin.css如下：</p><figure class="highlight javascript"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs javascript">body {<br>  padding-<span class="hljs-attr">top</span>: 40px;<br>  padding-<span class="hljs-attr">bottom</span>: 40px;<br>  background-<span class="hljs-attr">color</span>: #eee;<br>}<br><br>.<span class="hljs-property">form</span>-signin {<br>  max-<span class="hljs-attr">width</span>: 330px;<br>  <span class="hljs-attr">padding</span>: 15px;<br>  <span class="hljs-attr">margin</span>: <span class="hljs-number">0</span> auto;<br>}<br>.<span class="hljs-property">form</span>-signin .<span class="hljs-property">form</span>-signin-heading,<br>.<span class="hljs-property">form</span>-signin .<span class="hljs-property">checkbox</span> {<br>  margin-<span class="hljs-attr">bottom</span>: 10px;<br>}<br>.<span class="hljs-property">form</span>-signin .<span class="hljs-property">checkbox</span> {<br>  font-<span class="hljs-attr">weight</span>: normal;<br>}<br>.<span class="hljs-property">form</span>-signin .<span class="hljs-property">form</span>-control {<br>  <span class="hljs-attr">position</span>: relative;<br>  <span class="hljs-attr">height</span>: auto;<br>  -webkit-box-<span class="hljs-attr">sizing</span>: border-box;<br>     -moz-box-<span class="hljs-attr">sizing</span>: border-box;<br>          box-<span class="hljs-attr">sizing</span>: border-box;<br>  <span class="hljs-attr">padding</span>: 10px;<br>  font-<span class="hljs-attr">size</span>: 16px;<br>}<br>.<span class="hljs-property">form</span>-signin .<span class="hljs-property">form</span>-<span class="hljs-attr">control</span>:focus {<br>  z-<span class="hljs-attr">index</span>: <span class="hljs-number">2</span>;<br>}<br>.<span class="hljs-property">form</span>-signin input[type=<span class="hljs-string">"email"</span>] {<br>  margin-<span class="hljs-attr">bottom</span>: -1px;<br>  border-bottom-right-<span class="hljs-attr">radius</span>: <span class="hljs-number">0</span>;<br>  border-bottom-left-<span class="hljs-attr">radius</span>: <span class="hljs-number">0</span>;<br>}<br>.<span class="hljs-property">form</span>-signin input[type=<span class="hljs-string">"password"</span>] {<br>  margin-<span class="hljs-attr">bottom</span>: 10px;<br>  border-top-left-<span class="hljs-attr">radius</span>: <span class="hljs-number">0</span>;<br>  border-top-right-<span class="hljs-attr">radius</span>: <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></tbody></table></figure><p>images目录下保存bbs-favicon.ico。</p><p>其中，signin.css和bbs-favicon.ico可以从BootStrap模板中获取，演示如下：</p><p><img src="https://img.qxz5637.top/images/qexo/2025/06/01/2f23b33255038ebe9e3e6273e10614ce.gif"></p><p>运行主程序，访问<a href="https://cloud.tencent.com/developer/tools/blog-entry?target=http://127.0.0.1:5000/cms/login/&amp;objectId=1667396&amp;objectType=1&amp;isNewArticle=undefined">http://127.0.0.1:5000/cms/login/</a>，显示：</p><p><img src="https://img.qxz5637.top/images/qexo/2025/06/01/9197c9750b6b8327dca49581b152e7d4.png"></p><p>显然，登录模板已经基本实现。</p><p>原文链接：<a href="https://cloud.tencent.com/developer/article/1667396?policyId=1004">Python全栈（八）Flask项目实战之1.项目搭建-腾讯云开发者社区-腾讯云</a>)</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Flask项目实战之一-项目搭建&quot;&gt;&lt;a href=&quot;#Flask项目实战之一-项目搭建&quot; class=&quot;headerlink&quot; title=&quot;Flask项目实战之一.项目搭建&quot;&gt;&lt;/a&gt;Flask项目实战之一.项目搭建&lt;/h1&gt;&lt;p&gt;文章目录&lt;/p&gt;
&lt;ul&gt;
</summary>
      
    
    
    
    <category term="学习" scheme="https://www.qxz5637.top/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    <category term="网络" scheme="https://www.qxz5637.top/categories/%E7%BD%91%E7%BB%9C/"/>
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>WireGuard+udp2raw异地组网配置过程</title>
    <link href="https://www.qxz5637.top/2025/05/30/WireGuard+udp2raw%E5%BC%82%E5%9C%B0%E7%BB%84%E7%BD%91%E9%85%8D%E7%BD%AE%E8%BF%87%E7%A8%8B/"/>
    <id>https://www.qxz5637.top/2025/05/30/WireGuard+udp2raw%E5%BC%82%E5%9C%B0%E7%BB%84%E7%BD%91%E9%85%8D%E7%BD%AE%E8%BF%87%E7%A8%8B/</id>
    <published>2025-05-29T22:53:03.148Z</published>
    <updated>2025-05-29T22:53:03.741Z</updated>
    
    <content type="html"><![CDATA[<h1 id="WireGuard-udp2raw异地组网配置过程"><a href="#WireGuard-udp2raw异地组网配置过程" class="headerlink" title="WireGuard+udp2raw异地组网配置过程"></a>WireGuard+udp2raw异地组网配置过程</h1><h3 id="WireGuard设置过程"><a href="#WireGuard设置过程" class="headerlink" title="WireGuard设置过程"></a>WireGuard设置过程</h3><h4 id="安装wireguard"><a href="#安装wireguard" class="headerlink" title="安装wireguard"></a>安装wireguard</h4><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><br><span class="hljs-built_in">sudo</span> apt update<br><span class="hljs-built_in">sudo</span> apt install wireguard 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="生成本地公私钥"><a href="#生成本地公私钥" class="headerlink" title="生成本地公私钥"></a>生成本地公私钥</h4><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><br>wg genkey | <span class="hljs-built_in">sudo</span> <span class="hljs-built_in">tee</span> /etc/wireguard/privatekey | wg pubkey | <span class="hljs-built_in">sudo</span> <span class="hljs-built_in">tee</span> /etc/wireguard/publickey<br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="编辑连接wg0的配置"><a href="#编辑连接wg0的配置" class="headerlink" title="编辑连接wg0的配置"></a>编辑连接wg0的配置</h4><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><br><span class="hljs-built_in">sudo</span> nano /etc/wireguard/wg0.conf<br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="VPS主机-配置文件内容："><a href="#VPS主机-配置文件内容：" class="headerlink" title="VPS主机-配置文件内容："></a>VPS主机-配置文件内容：</h4><figure class="highlight makefile"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs makefile"><br>[Interface]<br>Address = 10.10.5.2/32<br>ListenPort = 5632<br>PrivateKey = PrivateKey<br><br>[Peer]<br>PublicKey = PublicKey<br>AllowedIPs = 10.10.5.2/32,192.168.1.0/24<br><span class="hljs-comment">#Endpoint = ip or domain:51820</span><br>PersistentKeepalive = 10<br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="内网主机-配置文件内容："><a href="#内网主机-配置文件内容：" class="headerlink" title="内网主机-配置文件内容："></a>内网主机-配置文件内容：</h4><figure class="highlight makefile"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs makefile"><br>[Interface]<br>Address = 10.10.5.1/32<br>ListenPort = 51820<br>PrivateKey = PrivateKey<br>PostUp = iptables -A FORWARD -i %i -j ACCEPT<br>PostUp = iptables -A FORWARD -o %i -j ACCEPT<br>PostUp = iptables -t nat -A POSTROUTING -s 10.10.5.0/24 -j SNAT --to-source 192.168.1.194<br>PostDown = iptables -D FORWARD -i %i -j ACCEPT<br>PostDown = iptables -D FORWARD -o %i -j ACCEPT<br>PostDown = iptables -t nat -D POSTROUTING -s 10.10.5.0/24 -j SNAT --to-source 192.168.1.194<br><span class="hljs-comment">#MTU = 1200</span><br><br>[Peer]<br>PublicKey = PublicKey<br>AllowedIPs = 10.10.5.2/32<br>Endpoint = 127.0.0.1:5632<br>PersistentKeepalive = 10<br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="内网主机开启数据转发"><a href="#内网主机开启数据转发" class="headerlink" title="内网主机开启数据转发"></a>内网主机开启数据转发</h4><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><br><span class="hljs-built_in">echo</span> <span class="hljs-string">'net.ipv4.ip_forward=1'</span> | <span class="hljs-built_in">sudo</span> <span class="hljs-built_in">tee</span> -a /etc/sysctl.conf<br><span class="hljs-built_in">sudo</span> sysctl -p 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="修改全部文件权限"><a href="#修改全部文件权限" class="headerlink" title="修改全部文件权限"></a>修改全部文件权限</h4><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><br><span class="hljs-built_in">sudo</span> <span class="hljs-built_in">chmod</span> 600 /etc/wireguard/*<br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="随启动运行"><a href="#随启动运行" class="headerlink" title="随启动运行"></a>随启动运行</h4><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash"><br><span class="hljs-built_in">sudo</span> systemctl <span class="hljs-built_in">enable</span> wg-quick@wg0<br><br><span class="hljs-built_in">sudo</span> systemctl start wg-quick@wg0<br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="VPS端-注意防火墙要打开5632"><a href="#VPS端-注意防火墙要打开5632" class="headerlink" title="VPS端 注意防火墙要打开5632"></a>VPS端 注意防火墙要打开5632</h4><h4 id="重启wg0接口"><a href="#重启wg0接口" class="headerlink" title="重启wg0接口"></a>重启wg0接口</h4><figure class="highlight x86asm"><table><tbody><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><code class="hljs x86asm"><br>wg-quick <span class="hljs-meta">down</span> wg0 &amp;&amp; wg-quick <span class="hljs-meta">up</span> wg0<br> 复制<br></code></pre></td></tr></tbody></table></figure><h3 id="udp2raw部分"><a href="#udp2raw部分" class="headerlink" title="udp2raw部分"></a>udp2raw部分</h3><h4 id="下载udp2raw"><a href="#下载udp2raw" class="headerlink" title="下载udp2raw"></a>下载udp2raw</h4><figure class="highlight bash"><table><tbody><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><code class="hljs bash"><br><span class="hljs-built_in">mkdir</span> udp2raw<br><span class="hljs-built_in">cd</span> udp2raw<br>wget https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz<br><br>tar -xzf udp2raw_binaries.tar.gz 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="server-sh-服务端脚本"><a href="#server-sh-服务端脚本" class="headerlink" title="server.sh 服务端脚本"></a>server.sh 服务端脚本</h4><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash"><br><span class="hljs-comment">#!/bin/bash</span><br><br><span class="hljs-built_in">nohup</span> /root/udp2raw/udp2raw_amd64 -s -l0.0.0.0:30005 -r127.0.0.1:5632 -k <span class="hljs-string">"pass"</span> --raw-mode faketcp --cipher-mode xor&nbsp; -a &gt; /root/udp2raw/udp_16400.<span class="hljs-built_in">log</span> 2&gt;&amp;1 &amp;<br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="client-sh-客户端脚本"><a href="#client-sh-客户端脚本" class="headerlink" title="client.sh 客户端脚本"></a>client.sh 客户端脚本</h4><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash"><br><span class="hljs-comment">#!/bin/bash</span><br><br><span class="hljs-built_in">nohup</span> /root/udp2raw/udp2raw_amd64 -c -l0.0.0.0:5632 -r141.11.175.39:30005 -k <span class="hljs-string">"pass"</span> --raw-mode faketcp --cipher-mode xor&nbsp; -a &gt; /root/udp2raw/udp_16400.<span class="hljs-built_in">log</span> 2&gt;&amp;1 &amp;<br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="修改本地主机的wg0配置文件"><a href="#修改本地主机的wg0配置文件" class="headerlink" title="修改本地主机的wg0配置文件"></a>修改本地主机的wg0配置文件</h4><figure class="highlight abnf"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs abnf"><span class="hljs-number">1</span>.添加MTU <span class="hljs-operator">=</span> <span class="hljs-number">1200</span><br><span class="hljs-number">2</span>.修改接入点地址  复制<br></code></pre></td></tr></tbody></table></figure><h4 id="stop-sh-停止后台运行脚本"><a href="#stop-sh-停止后台运行脚本" class="headerlink" title="stop.sh 停止后台运行脚本"></a>stop.sh 停止后台运行脚本</h4><figure class="highlight bash"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs bash"><br><span class="hljs-comment">#!/bin/bash</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"Stopping udp2raw instances..."</span><br>pids=$(ps aux | grep udp2raw_amd64 | grep -v grep | awk <span class="hljs-string">'{print $2}'</span>)<br><span class="hljs-keyword">for</span> pid <span class="hljs-keyword">in</span> <span class="hljs-variable">$pids</span>; <span class="hljs-keyword">do</span><br>&nbsp; &nbsp; <span class="hljs-built_in">kill</span> -9 <span class="hljs-variable">$pid</span><br>&nbsp; &nbsp; <span class="hljs-built_in">echo</span> <span class="hljs-string">"Stopped process with PID <span class="hljs-variable">$pid</span>"</span><br><span class="hljs-keyword">done</span><br><span class="hljs-built_in">echo</span> <span class="hljs-string">"All udp2raw instances stopped."</span><br> 复制<br></code></pre></td></tr></tbody></table></figure><h4 id="udp2raw各参数释义"><a href="#udp2raw各参数释义" class="headerlink" title="udp2raw各参数释义"></a>udp2raw各参数释义</h4><table><thead><tr><th>选项</th><th>注释</th></tr></thead><tbody><tr><td>–raw-mode</td><td>伪装模式，支持 faketcp/udp/icmp，用于绕过防火墙</td></tr><tr><td>-k,–key</td><td>密码设置</td></tr><tr><td><code>--cipher-mode</code></td><td>加密模式（如<code>aes128cbc</code>）</td></tr><tr><td><code>--auth-mode</code></td><td>认证模式（如<code>md5</code>/<code>crc32</code>）</td></tr><tr><td>-a,–auto-rule</td><td>自动管理iptables规则</td></tr><tr><td>-g,–gen-rule</td><td>自动生成 iptables 规则</td></tr><tr><td>–disable-anti-replay</td><td>禁用反重放保护功能</td></tr><tr><td>–source-ip</td><td>服务端IP地址</td></tr><tr><td>–source-port</td><td>服务端端口号</td></tr><tr><td>–conf-file</td><td>指定配置文件</td></tr><tr><td>–fifo</td><td>向运行中的程序发送命令</td></tr><tr><td>–log-level</td><td>日志级别（<code>0</code>静默,<code>1</code>错误,<code>2</code>警告,<code>3</code>信息）</td></tr><tr><td>–log-position</td><td>设置日志文件名</td></tr><tr><td>–disable-color</td><td>禁用日志颜色输出</td></tr><tr><td>–disable-bpf</td><td></td></tr><tr><td>–sock-buf</td><td>设置 socket 缓冲区大小</td></tr><tr><td>–force-sock-buf</td><td></td></tr><tr><td>–seq-mode</td><td></td></tr><tr><td>–lower-level</td><td>MAK地址</td></tr><tr><td>–gen-add</td><td></td></tr><tr><td>–keep-rule</td><td>定期主动检查 iptables 规则</td></tr><tr><td>–clear</td><td>清除iptables规则</td></tr></tbody></table><h4 id="原文连接："><a href="#原文连接：" class="headerlink" title="原文连接："></a>原文连接：</h4><p><a href="https://www.milaone.com/archives/163.html">WireGuard+udp2raw异地组网配置过程</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;WireGuard-udp2raw异地组网配置过程&quot;&gt;&lt;a href=&quot;#WireGuard-udp2raw异地组网配置过程&quot; class=&quot;headerlink&quot; title=&quot;WireGuard+udp2raw异地组网配置过程&quot;&gt;&lt;/a&gt;WireGuard+u</summary>
      
    
    
    
    <category term="网络" scheme="https://www.qxz5637.top/categories/%E7%BD%91%E7%BB%9C/"/>
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
    <category term="网络" scheme="https://www.qxz5637.top/tags/%E7%BD%91%E7%BB%9C/"/>
    
  </entry>
  
  <entry>
    <title>MariaDB设置密码</title>
    <link href="https://www.qxz5637.top/2025/05/28/MariaDB%E5%AF%86%E7%A0%81%E8%AE%BE%E7%BD%AE/"/>
    <id>https://www.qxz5637.top/2025/05/28/MariaDB%E5%AF%86%E7%A0%81%E8%AE%BE%E7%BD%AE/</id>
    <published>2025-05-28T12:38:38.114Z</published>
    <updated>2025-05-28T12:47:44.018Z</updated>
    
    <content type="html"><![CDATA[<h1 id="MariaDB设置密码"><a href="#MariaDB设置密码" class="headerlink" title="MariaDB设置密码"></a>MariaDB设置密码</h1><p>如果在安装MariaDB的过程中没有设置root用户的密码，或者忘记了设置的密码，可以通过以下步骤来重置MariaDB的root密码：</p><h3 id="1-停止MariaDB服务"><a href="#1-停止MariaDB服务" class="headerlink" title="1. 停止MariaDB服务"></a>1. 停止MariaDB服务</h3><p>首先，需要停止MariaDB服务。使用以下命令：</p><figure class="highlight arduino"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs arduino">systemctl stop mariadb<br></code></pre></td></tr></tbody></table></figure><h3 id="2-以无密码模式启动MariaDB"><a href="#2-以无密码模式启动MariaDB" class="headerlink" title="2. 以无密码模式启动MariaDB"></a>2. 以无密码模式启动MariaDB</h3><p>接下来，以无密码模式（即跳过权限表验证）启动MariaDB：</p><figure class="highlight haskell"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs haskell"><span class="hljs-title">mariadbd</span>-<span class="hljs-keyword">safe</span> <span class="hljs-comment">--skip-grant-tables &amp;</span><br></code></pre></td></tr></tbody></table></figure><p>这里的<code>&amp;</code>符号使得mariadbd-safe在后台运行，你可以继续在终端中操作。</p><h3 id="3-登录MariaDB"><a href="#3-登录MariaDB" class="headerlink" title="3. 登录MariaDB"></a>3. 登录MariaDB</h3><p>由于是以无密码模式启动的，所以可以直接登录MariaDB，不需要输入密码：</p><figure class="highlight ebnf"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">mariadb -u root</span><br></code></pre></td></tr></tbody></table></figure><h3 id="4-重置root密码"><a href="#4-重置root密码" class="headerlink" title="4. 重置root密码"></a>4. 重置root密码</h3><p>登录后，选择MariaDB的<code>mysql</code>数据库，然后重置root用户的密码。执行以下SQL命令：</p><figure class="highlight pgsql"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs pgsql">USE mysql;  <br>  <br><span class="hljs-comment">-- 更新root用户的密码，这里假设你要设置的密码是'new_password'  </span><br><span class="hljs-keyword">UPDATE</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">SET</span> authentication_string=<span class="hljs-keyword">PASSWORD</span>(<span class="hljs-string">'new_password'</span>) <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">User</span>=<span class="hljs-string">'root'</span>;  <br>  <br><span class="hljs-comment">-- 刷新权限  </span><br>FLUSH <span class="hljs-keyword">PRIVILEGES</span>;  <br>  <br><span class="hljs-comment">-- 退出MariaDB  </span><br><span class="hljs-keyword">EXIT</span>;<br></code></pre></td></tr></tbody></table></figure><p>请注意，从MariaDB 10.4开始，<code>PASSWORD()</code>函数已被弃用，应使用<code>ALTER USER</code>命令来设置密码，如下所示：</p><figure class="highlight pgsql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs pgsql"><span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">USER</span> <span class="hljs-string">'root'</span>@<span class="hljs-string">'localhost'</span> IDENTIFIED <span class="hljs-keyword">BY</span> <span class="hljs-string">'new_password'</span>;<br></code></pre></td></tr></tbody></table></figure><h3 id="5-重启MariaDB服务"><a href="#5-重启MariaDB服务" class="headerlink" title="5. 重启MariaDB服务"></a>5. 重启MariaDB服务</h3><p>现在，以正常模式重启MariaDB服务：</p><figure class="highlight ebnf"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">systemctl restart mariadb</span><br></code></pre></td></tr></tbody></table></figure><h3 id="6-使用新密码登录"><a href="#6-使用新密码登录" class="headerlink" title="6. 使用新密码登录"></a>6. 使用新密码登录</h3><p>使用新设置的密码登录MariaDB：</p><figure class="highlight css"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs css">mariadb -u root -<span class="hljs-selector-tag">p</span><br></code></pre></td></tr></tbody></table></figure><p>系统会提示你输入密码，输入你在上面步骤中设置的新密码<code>new_password</code>。</p><p>完成这些步骤后，你就应该能够使用新密码登录MariaDB了。记得将<code>new_password</code>替换为你实际想要设置的密码，并确保密码足够复杂和安全。</p><p>如果你之前安装MariaDB时设置了密码，但忘记了，那么上述步骤同样适用，只是你需要用你尝试过的旧密码替换掉<code>new_password</code>，然后重新设置一个新密码。如果你完全不知道密码，则上述步骤将帮助你重置它。</p><p>参考连接：<a href="https://www.cnblogs.com/music-liang/p/18081929">MariaDB设置密码</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;MariaDB设置密码&quot;&gt;&lt;a href=&quot;#MariaDB设置密码&quot; class=&quot;headerlink&quot; title=&quot;MariaDB设置密码&quot;&gt;&lt;/a&gt;MariaDB设置密码&lt;/h1&gt;&lt;p&gt;如果在安装MariaDB的过程中没有设置root用户的密码，或者忘记</summary>
      
    
    
    
    <category term="学习" scheme="https://www.qxz5637.top/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    <category term="电脑" scheme="https://www.qxz5637.top/categories/%E7%94%B5%E8%84%91/"/>
    
    
    <category term="数据库" scheme="https://www.qxz5637.top/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位</title>
    <link href="https://www.qxz5637.top/2025/05/28/%E9%A2%86%E8%8B%B1%E9%AB%98%E7%AE%A1%E8%AD%A6%E5%91%8A%EF%BC%9AAI%E6%AD%A3%E5%9C%A8%E5%86%B2%E5%87%BB%E2%80%9CZ%E4%B8%96%E4%BB%A3%E2%80%9D%E8%81%8C%E4%B8%9A%E7%94%9F%E6%B6%AF%E7%9A%84%E8%B5%B7%E7%82%B9%E5%B2%97%E4%BD%8D/"/>
    <id>https://www.qxz5637.top/2025/05/28/%E9%A2%86%E8%8B%B1%E9%AB%98%E7%AE%A1%E8%AD%A6%E5%91%8A%EF%BC%9AAI%E6%AD%A3%E5%9C%A8%E5%86%B2%E5%87%BB%E2%80%9CZ%E4%B8%96%E4%BB%A3%E2%80%9D%E8%81%8C%E4%B8%9A%E7%94%9F%E6%B6%AF%E7%9A%84%E8%B5%B7%E7%82%B9%E5%B2%97%E4%BD%8D/</id>
    <published>2025-05-28T08:33:39.430Z</published>
    <updated>2025-05-28T08:38:49.251Z</updated>
    
    <content type="html"><![CDATA[<h1 id="领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位"><a href="#领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位" class="headerlink" title="领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位"></a>领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位</h1><blockquote><p><em>企业并未彻底取消初级岗位，许多管理者依然希望从年轻员工那里获得新鲜创意。同时，AI的普及也在一定程度上让新人有机会更早承担较为高级的工作任务。</em></p></blockquote><p>“首当其冲的是职业阶梯的最底层。”近日，领英首席经济机会官阿尼什·拉曼（Aneesh Raman）公开表示，AI正以前所未有的速度取代很多帮助“Z世代”（通常指1995年-2009年出生的一代人，也称“互联网世代”）开启职场生涯的初级岗位。数据驱动型风险投资公司SignalFire分析了领英上超6亿员工和8000万家公司的人才流动数据，发现科技巨头企业2024年的应届毕业生招聘人数较2023年下降了25%，初创企业则减少11%。</p><p>“目前，最早感受到AI冲击的领域是科技行业。未来金融、旅游、餐饮等多个行业也将逐步受到波及。”拉曼指出，AI已可以完成初级软件工程师的基础编码与调试任务，而这是过去初级软件开发人员积累经验的途径。Rogo公司创始人、前Lazard银行分析师Gabe Stengel表示，“AI能生成报告材料、完成尽调、查看财务数据”，几乎可以完成其过去为分析生物科技企业所做的一切工作。</p><p>值得注意的是，尽管AI对初级岗位构成威胁，但科技公司对经验人才的需求在持续上升。SignalFire的数据显示，科技巨头企业对拥有2至5年经验的专业人才招聘增长27%，初创公司这一增幅为14%。</p><p>尽管还缺乏确凿证据说明AI是导致毕业生就业难的直接原因，但SignalFire研究主管Asher Bantock认为，已存在有力证据表明AI是主要影响因素之一。初级岗位由于多为例行性、低风险任务，更易被生成式AI取代。</p><p>不过，拉曼补充，企业并未彻底取消初级岗位，许多管理者依然希望从年轻员工那里获得新鲜创意。同时，AI的普及也在一定程度上让新人有机会更早承担较为高级的工作任务。他建议，企业应该为初级岗位分配更具挑战性的任务。</p><p>一些企业已开始作出调整。AI内容生成平台Jasper AI的CEO Timothy Young认为，“智能的商品化”意味着雇佣最聪明的人已不再是核心，培养员工的管理能力愈发重要。“年轻员工依然具有巨大价值，但用人方式必须改变。”他表示，企业应看重求职者的好奇心和韧性。</p><p>然而，Indeed公司CEO Chris Hyams指出，AI并不能完全取代人类岗位。与此同时，包括语言学习应用公司Duolingo和金融科技公司Klarna在内的多家企业，也正在收回对“用AI取代人类”的激进态度。</p><p>研究结果也表明，AI并未如预期那样迅速改变就业市场。IBM的一项调查显示，四分之三的AI项目未能实现预期投资回报；美国国家经济研究局（NBER）对AI高暴露行业的研究发现，这些岗位在薪资或工作时长上的变化微乎其微。</p><p>“如果只从技术潜力角度去想象AI的冲击，可能会高估它的实际影响。”芝加哥大学经济学教授、该研究的合著者Anders Humlum表示，“但眼下这场转变既缓慢，也远小于预期。”</p><p>原文连接：<a href="https://www.thepaper.cn/newsDetail_forward_30891118">领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位&quot;&gt;&lt;a href=&quot;#领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位&quot; class=&quot;headerlink&quot; title=&quot;领英高管警告：AI正在冲击“Z世代”职业生涯的起点岗位&quot;&gt;&lt;/a&gt;领英高管警</summary>
      
    
    
    
    <category term="新闻" scheme="https://www.qxz5637.top/categories/%E6%96%B0%E9%97%BB/"/>
    
    
    <category term="新闻" scheme="https://www.qxz5637.top/tags/%E6%96%B0%E9%97%BB/"/>
    
  </entry>
  
  <entry>
    <title>无论男女，中年以后，没有特殊经济困难，不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，而且也赚不到什么钱</title>
    <link href="https://www.qxz5637.top/2025/05/22/%E6%B2%A1%E6%9C%89%E7%89%B9%E6%AE%8A%E7%BB%8F%E6%B5%8E%E5%9B%B0%E9%9A%BE%EF%BC%8C%E4%B8%8D%E8%A6%81%E7%94%A8%E6%97%B6%E9%97%B4%E5%92%8C%E4%BD%93%E5%8A%9B%E6%8D%A2%E9%92%B1/"/>
    <id>https://www.qxz5637.top/2025/05/22/%E6%B2%A1%E6%9C%89%E7%89%B9%E6%AE%8A%E7%BB%8F%E6%B5%8E%E5%9B%B0%E9%9A%BE%EF%BC%8C%E4%B8%8D%E8%A6%81%E7%94%A8%E6%97%B6%E9%97%B4%E5%92%8C%E4%BD%93%E5%8A%9B%E6%8D%A2%E9%92%B1/</id>
    <published>2025-05-22T10:45:44.122Z</published>
    <updated>2025-05-22T10:45:44.122Z</updated>
    
    <content type="html"><![CDATA[<h1 id="无论男女，中年以后，没有特殊经济困难，不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，而且也赚不到什么钱！"><a href="#无论男女，中年以后，没有特殊经济困难，不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，而且也赚不到什么钱！" class="headerlink" title="无论男女，中年以后，没有特殊经济困难，不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，而且也赚不到什么钱！"></a>无论男女，中年以后，没有特殊经济困难，不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，而且也赚不到什么钱！</h1><p><img src="https://img.qxz5637.top/images/picgo/2025/05/21/20250521163405345.jpeg"></p><p>李宗盛《凡人歌》里唱到： “你我皆凡人，生在人世间，终日奔波苦，一刻不得闲，既然不是仙，难免有杂念……” 人到中年是最难的，上有老下有小，什么地方都要钱。 于是，疲于奔波，不敢停歇，结果一步步累垮了自己。 随着年龄渐长，渐渐悟透了</p><p>李宗盛《凡人歌》里唱到：</p><p><strong>“你我皆凡人，生在人世间，终日奔波苦，一刻不得闲，既然不是仙，难免有杂念……”</strong></p><p>人到中年是最难的，上有老下有小，什么地方都要钱。</p><p>于是，疲于奔波，不敢停歇，结果一步步累垮了自己。</p><p><strong>随着年龄渐长，渐渐悟透了一个道理：</strong></p><p><strong>如果没有特殊经济困难，千万不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，还赚不到什么钱。</strong></p><p> <strong>01</strong> <strong>人，永远不要赚太辛苦的钱</strong></p><p>电视剧《天道》里，讲过这样一个故事。</p><p>王庙村的村民们，明明勤劳能干，却摆脱不了贫穷的命运，有的人甚至连4块钱的电费也交不起。</p><p>丁元英来到这里后，发现了问题所在：</p><p>村民们的穷，不是因为不努力，而是生存观念出了问题。</p><p>大部分人只知道埋头种地，靠天吃饭，用卖命劳作换个勉强糊口。</p><p>小部分人会去城里打工，在太阳底下搬砖、拉货，一旦碰上黑心老板或者同行竞争，就立马卷铺盖回家。</p><p>政府出资建了翻砂厂、木工坊，可一看赚不过城里的大工厂，村民们就自暴自弃，任由厂子荒废、闲置。</p><p>他们宁愿忍受贫穷，也不愿意好好想想生活的其他出路；宁愿在痛苦中煎熬，也不愿意承担风险多尝试。</p><p>就这样，在一次次的“趋易避难”中，祖祖辈辈无法翻身。</p><p><img src="https://img.qxz5637.top/images/picgo/2025/05/21/20250521163618816.png"></p><p>现实中，很多人也是如此，明明非常努力的工作，一年到头没休息几天，却还是只能混个温饱，升职加薪没有他，裁员第一个就是他。</p><p>经济学家阿比吉特曾提过一个概念“贫穷的循环”，完美地解释了这种现象的出现：</p><p>一个人收入下降，就会想要做更多工作去挣钱，没有时间提升自己，只知道重复劳动。</p><p>结果就是，工作时间增加了，收入反而更少了，然后再次重复这个过程。</p><p>很多时候，人之所以赚不到钱，就是因为“太忙了”，忙着用时间和体力换钱，只有努力没有价值，甚至危害到自己的身体健康。</p><p>纪录片《人间世》里就有个令人心痛的案例：</p><p>正值盛年的戴向群，为了每月多赚一两千块钱，在满是金属粉尘的车间，当了十年磨砂工。</p><p>结果钱没存下多少，却得了严重的尘肺病，只能躺在床上靠呼吸机续命，挣的钱还不够自己的医药费。</p><p>有段话说的扎心却很真实：</p><p>要抢救的时候，才知道救护车是最贵的车；要住院的时候，才明白病床是最贵的床；要拿药的时候，才懂得药方是最贵的纸……</p><p>人所能犯的最大错误，就是用健康换钱。</p><p><strong>以为自己是为家人好，殊不知错误的挣钱方式，不仅赚不到钱，还给家人带去巨大的负担。</strong></p><p><strong>真正成熟、有担当的中年人，都懂得先照顾好自己，只有自己好好的，整个家才能幸福快乐。</strong></p><p><img src="https://img.qxz5637.top/images/picgo/2025/05/21/20250521163715758.jpeg"></p><p> <strong>02</strong> <strong>认知水平，是一个人的核心竞争力</strong></p><p>很赞同洛克菲勒说的一句话：</p><p><strong>“财富是对认知的补偿，而不是对勤奋的奖赏。口袋里的钱，是脑袋里认知的变现。”</strong></p><p>社会学家谢宇曾走访过这样一个小镇。</p><p>小镇中，有很多个体商户，大部分店都开到深夜，只有少数几家每到日暮就打烊。</p><p>谢宇觉得，这些早早就关门的店，生意一定不好，因为这些商户“不够勤劳”。</p><p>可经过一番调研后，他推翻了自己的结论。</p><p>那些开到深夜的店，生意都很差，因为他们只是依靠延长时间来维持经营，没有一点儿新意。</p><p>而那些提前打烊的店，都把时间花在了改善品类、提高口感上，还时不时做一些新颖的活动，吸引客人消费，生意自然越来越好。</p><p>无独有偶，很多人可能都听过帕梅拉这个名字。</p><p>帕梅拉是一个德国健身博主，15岁起每天坚持在网上分享健身日常。</p><p>在发现很多人想要健身，却没有去健身房的条件时，她立刻抓住了这个机遇，设计了一套室内健身方案，一张瑜伽垫、一瓶矿泉水，随时随地就能开始锻炼。</p><p>因为抓住了人们的心理，且视频效果确实显著，她迅速火遍全球。</p><p>此外，她还会给粉丝分享各类健身减脂食谱，推出健身APP，将健身经验写成书，发行当月就拿下亚马逊畅销图书榜第一名。</p><p>如今，帕梅拉每年单靠视频点击量，就可以赚到上百万广告费，还登上了《福布斯》杂志的封面。</p><p>有人说：“未来社会不是人赚钱，而是钱找人，财富永远只会流向最匹配它的人。”</p><p>说的很对，机会永远是留给有准备的人。</p><p><strong>很多时候，拉开人与人差距的，从来不是外部条件，而是认知上的不同。</strong></p><p>仅仅知道不停地干活是不够的，不过是用低水平的勤奋，来掩饰自己从不思考的懒惰。</p><p><strong>只有跳脱出繁忙的工作，学会深度思考，用头脑赚钱，人生才会发生改变。</strong></p><p><img src="https://img.qxz5637.top/images/picgo/2025/05/21/20250521163759001.jpeg"></p><p> <strong>03</strong> <strong>人到中年，别把日子过反了</strong></p><p>俞敏洪曾说：</p><p><strong>“很多人一辈子有两个追求，一个是有钱，一个是值钱；有钱的人不一定值钱，但值钱的人一定会有钱。”</strong></p><p>人到中年，与其在重复且无意义的体力工作中拼命，用身体换财富；</p><p>不如努力学习，提升自己的认知和眼界，让自己变成“值钱的人”。</p><p>当你的思维转变了，自会离财富越来越近，生活也会越来越幸福。</p><p><strong>（一）保持健康，健康是一切的基础</strong></p><p>树立家庭观念：真正对家人好，不是盲目地拼命挣钱，而是先照顾好自己的身体，将健康放在首位，才能当好家庭的顶梁柱。</p><p>转变工作观念：工作是为了挣钱，挣钱是为了更好的生活，更好生活的前提是身心健康，没有健康，挣再多的钱也是无用。</p><p><strong>人生下半场，拼的是健康，身体无病，心里无事，是幸福生活的基础和前提。</strong></p><p><strong>（二）提升认知，转变自己的思维</strong></p><p>多读书，开阔眼界：书籍类型可以涵盖多领域，如历史、哲学、科学等，拓宽自己的知识面和视野，从书中汲取智慧和力量，打破思维局限。</p><p>练技能，提高专业性：结合自己的工作和兴趣，学习新的技能，例如考证书、报专业课程等，提高在工作中的竞争力，为职业发展打下坚实基础。</p><p>追时代，抓住风口：关注社会发展动态和新兴行业趋势，例如如今的AI领域，利用新兴技术为自己创造更多机会，实现弯道超车。</p><p><strong>一个人，永远都赚不到自己认知以外的钱，提升认知，是赚钱的核心。</strong></p><p><strong>（三）定期自我反思，持续成长进步</strong></p><p>定期复盘，回顾自己一段时间内的工作和生活，总结成功经验和失败教训，找出自己的不足之处，思考改进的方法和措施。</p><p>建立目标，根据自己的现状和需求，设定短期目标或长期目标，如半年内学会一项新技能，5 - 10年攒够多少钱等，制定合理的规划，并逐步推进。</p><p>积极面对变化，当工作环境、生活方式发生改变时，将它视为成长的契机，而不是阻碍，不要焦虑，快速调整自己，走出舒适区，及时适应。</p><p><strong>思考是唯一一个，对任何人而言，没有门槛的逆袭机会。</strong></p><p><img src="https://img.qxz5637.top/images/picgo/2025/05/21/20250521163849773.jpeg"></p><p> <strong>04</strong> 很喜欢一句话：</p><p><strong>“人无法用一成不变的自己，去换一个充满希望的未来。”</strong></p><p>真正有智慧的中年人，都懂得什么才是最重要的。</p><p>若你发现，你的收入配不上辛苦，那就沉淀能力、思考未来；见识配不上年龄，那就打开视野、改变认知；要是能力配不上野心，那就静心学习、沉淀底蕴。</p><p><strong>人到中年，千万别把日子过反了，用健康换钱财，用未来换当下，最后徒留遗憾，无法重来。</strong></p><p>原文链接：<a href="https://www.msn.cn/zh-cn/news/other/%E6%97%A0%E8%AE%BA%E7%94%B7%E5%A5%B3-%E4%B8%AD%E5%B9%B4%E4%BB%A5%E5%90%8E-%E6%B2%A1%E6%9C%89%E7%89%B9%E6%AE%8A%E7%BB%8F%E6%B5%8E%E5%9B%B0%E9%9A%BE-%E4%B8%8D%E8%A6%81%E7%94%A8%E6%97%B6%E9%97%B4%E5%92%8C%E4%BD%93%E5%8A%9B%E6%8D%A2%E9%92%B1-%E8%BF%99%E6%98%AF%E9%9D%9E%E5%B8%B8%E6%84%9A%E8%A0%A2%E7%9A%84%E5%81%9A%E6%B3%95-%E7%9B%AE%E5%85%89%E7%9F%AD%E6%B5%85-%E8%80%8C%E4%B8%94%E4%B9%9F%E8%B5%9A%E4%B8%8D%E5%88%B0%E4%BB%80%E4%B9%88%E9%92%B1/ar-AA1FaZjF?ocid=msedgntp&amp;pc=U711&amp;cvid=682d8c80dc024cb7abd61360b740e36d&amp;ei=25">无论男女，中年以后，没有特殊经济困难，不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，而且也赚不到什么钱</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;无论男女，中年以后，没有特殊经济困难，不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，而且也赚不到什么钱！&quot;&gt;&lt;a href=&quot;#无论男女，中年以后，没有特殊经济困难，不要用时间和体力换钱，这是非常愚蠢的做法，目光短浅，而且也赚不到什么钱！&quot; class=&quot;h</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>VC Code测试通过插件上传图片</title>
    <link href="https://www.qxz5637.top/2025/05/22/VC%20Code%E6%B5%8B%E8%AF%95%E9%80%9A%E8%BF%87%E6%8F%92%E4%BB%B6%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87/"/>
    <id>https://www.qxz5637.top/2025/05/22/VC%20Code%E6%B5%8B%E8%AF%95%E9%80%9A%E8%BF%87%E6%8F%92%E4%BB%B6%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%87/</id>
    <published>2025-05-22T10:37:33.246Z</published>
    <updated>2025-05-22T10:37:34.212Z</updated>
    
    <content type="html"><![CDATA[<p>VC Code测试通过插件上传图片</p><p><img src="https://img.qxz5637.top/images/images/vscode/2025052207110607-4-201110135423315.jpg"></p><p>vscode minio picman 插件上传图片成功！<br>更改上传路径，再看看</p><p><img src="https://img.qxz5637.top/images/vscode/2025052209580552-1f178a82b9014a9082ecbc57db6a7614b21bee2a.jpeg"></p><p>成功了！使用这个路径，上面的路径作废。<br>该文件为用VC Code编辑后直接拷贝到Hexo文章发布文件夹。<br>没有写标题等信息，看不到。<br>补充信息后，再看看。</p><p>网站里面可以看到，但是Qexo中看不到。暂时放弃VC Code编辑MD文件了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;VC Code测试通过插件上传图片&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.qxz5637.top/images/images/vscode/2025052207110607-4-201110135423315.jpg&quot;&gt;&lt;/p&gt;
&lt;p&gt;vscode mi</summary>
      
    
    
    
    <category term="学习" scheme="https://www.qxz5637.top/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>测试用Qexo管理Hexo</title>
    <link href="https://www.qxz5637.top/2025/05/22/%E6%B5%8B%E8%AF%95%E7%94%A8Qexo%E7%AE%A1%E7%90%86Hexo/"/>
    <id>https://www.qxz5637.top/2025/05/22/%E6%B5%8B%E8%AF%95%E7%94%A8Qexo%E7%AE%A1%E7%90%86Hexo/</id>
    <published>2025-05-22T02:52:48.123Z</published>
    <updated>2025-05-22T04:17:57.418Z</updated>
    
    <content type="html"><![CDATA[<p>首先测试上传图片至自建的minio图库，上传成功，显示如下：</p><p><img src="https://img.qxz5637.top/images/qexo/2025/05/22/c33c80b9e81aeba91d3e29897b948b3d.png" alt="5b0988e595225.png"></p><p>其次，测试编辑发表文章。</p><p>看到这篇文章，就说明成功了！</p><p>minio图库设置截图如下：</p><p><img src="https://img.qxz5637.top/images/qexo/2025/05/22/332ebbeff0cabe0f67af095cb44fbac6.png"></p><p>👏</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;首先测试上传图片至自建的minio图库，上传成功，显示如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.qxz5637.top/images/qexo/2025/05/22/c33c80b9e81aeba91d3e29897b948b3d.png&quot; alt=</summary>
      
    
    
    
    <category term="网络" scheme="https://www.qxz5637.top/categories/%E7%BD%91%E7%BB%9C/"/>
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>有钱不去两地，没钱不求两人</title>
    <link href="https://www.qxz5637.top/2025/05/21/%E2%80%9C%E6%9C%89%E9%92%B1%E4%B8%8D%E5%8E%BB%E4%B8%A4%E5%9C%B0%EF%BC%8C%E6%B2%A1%E9%92%B1%E4%B8%8D%E6%B1%82%E4%B8%A4%E4%BA%BA%E2%80%9D%EF%BC%8C%E8%80%81%E7%A5%96%E5%AE%97%E7%9A%84%E5%BF%A0%E5%91%8A%EF%BC%8C%E7%8E%B0%E5%AE%9E%E5%8F%88%E5%BF%83%E9%85%B8%EF%BC%81/"/>
    <id>https://www.qxz5637.top/2025/05/21/%E2%80%9C%E6%9C%89%E9%92%B1%E4%B8%8D%E5%8E%BB%E4%B8%A4%E5%9C%B0%EF%BC%8C%E6%B2%A1%E9%92%B1%E4%B8%8D%E6%B1%82%E4%B8%A4%E4%BA%BA%E2%80%9D%EF%BC%8C%E8%80%81%E7%A5%96%E5%AE%97%E7%9A%84%E5%BF%A0%E5%91%8A%EF%BC%8C%E7%8E%B0%E5%AE%9E%E5%8F%88%E5%BF%83%E9%85%B8%EF%BC%81/</id>
    <published>2025-05-21T00:08:08.000Z</published>
    <updated>2025-05-21T01:19:54.856Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.qxz5637.top/images/picgo/2025/05/21/20250521084313921.jpeg"></p><h1 id="“有钱不去两地，没钱不求两人。”"><a href="#“有钱不去两地，没钱不求两人。”" class="headerlink" title="“有钱不去两地，没钱不求两人。”"></a>“有钱不去两地，没钱不求两人。”</h1><p>这话听起来有些辛酸，但却句句都是逆耳的忠言。</p><p>“两地”究竟是什么地方，“两人”又指哪两类人呢？让我们一起来看一看！</p><h1 id="01-有钱不去两地"><a href="#01-有钱不去两地" class="headerlink" title="01 有钱不去两地"></a><strong>01</strong> 有钱不去两地</h1><p><strong>1、不去奢侈之地</strong></p><p>《增广贤文》中有言：“<strong>兴家犹如针挑土，败家犹如水推沙。</strong>”</p><p>每份家业的积累，都是一个漫长的过程，就像针挑土一样困难；</p><p>但败家恰恰相反，犹如大水冲沙般，一个浪头打过来，就什么都不剩了。</p><p>老人常说：富不过三代。正是这个道理。</p><p>晚清名臣李鸿章去世，给子孙13000亩的良田，以及数不清的房产和白银。</p><p>他的孙子李子嘉，还不到20岁。面对手中的财富，他根本就不知道怎么安排，唯一想到的方式就是尽情地挥霍。</p><p>李子嘉每天往返于各种奢侈场所，不是出去花天酒地，就是在去一掷千金的路上。</p><p>再多的金钱也经不起肆意地挥霍，李子嘉现金没了就卖田产，田产卖光了就卖房产。</p><p>几经折腾，终于挥霍光了所有的财产，沦为流落街头的乞丐。</p><p><strong>一个家庭想要积累财富，往往需要经历几代人的共同努力。</strong></p><p><strong>一旦贪图奢侈享受，可能只需要一代人的时间，就会走向没落。</strong></p><p>再富裕的家庭，也经不起铺张浪费。</p><p>只有时刻保持节制与理性，家族才能长久兴旺。</p><p><img src="https://img.qxz5637.top/images/picgo/2025/05/21/20250521084500260.jpeg"></p><p><strong>2.不去是非之地</strong></p><p>《君子行》里说：“<strong>君子防未然，不处嫌疑间。瓜田不纳履，李下不整冠</strong>。”</p><p>人在有钱的时候，最容易树大招风，被“有心人”惦记。</p><p>做事应该懂得避嫌：经过别人瓜田的时候，不要弯腰去提鞋，不然容易让人怀疑你偷瓜；</p><p>走到别人李子树下，也不要用手去扶帽子，否则很像是动手去摘李子。</p><p>不去容易产生是非的场合，不给别人留下生事的话柄。</p><p>唐朝有个官员叫郭旼，家里是皇亲国戚，跟太后有亲戚关系。</p><p>郭旼经常让两个女儿，进宫去陪伴太后，引得朝野上下议论纷纷。</p><p>不久后，皇帝派他郭旼去江宁，让他做了个小官。</p><p>人们认为，是郭氏送了两个女儿入宫，才换来这个职位的。</p><p>郭旼非常苦恼，他向上司辩解，说女儿入宫是为陪伴太后，不是献给皇帝的。</p><p>上司说：“瓜田李下的嫌疑，外人哪里分得清呢？全怪你自己不注意罢了。”</p><p>凡是是非之地，一定是众人瞩目的焦点。</p><p><strong>很多人就是喜欢在这些地方逞能，处处显露自己，所以才会惹祸上身。</strong></p><h1 id="02-不求两人"><a href="#02-不求两人" class="headerlink" title="02 不求两人"></a><strong>02</strong> 不求两人</h1><p><strong>1、虚情假意的朋友</strong></p><p>老话说：“<strong>一贵一贱，交情乃见。</strong>”</p><p>有贫富之分，方可看出交情的深浅；有贵贱之别，才会发现谁是真心待自己好的人。</p><p>齐白石初到北京，没有任何名气，画风也不被认可。</p><p>一日，他去参加画展，很多名人来来往往，却没有一人留意到他的画。</p><p>直到画展快要结束时，才有一人驻足在他的画前。</p><p>只听那人道：“你们看这几幅画，虾会游，鸟会飞，真乃神作。”</p><p>齐白石则慌忙致谢，才发现这人正是京剧大师梅兰芳。</p><p>因为梅兰芳的欣赏，周围人纷纷开始跟风，大肆称赞齐白石的画。</p><p>可是真到了卖画时，仍旧无人问津，只有梅兰芳倾囊相助。</p><p>正所谓：<strong>烈火识真金，患难见人心。</strong></p><p>谁是真心，谁是假意，当你身处低谷，就能看得清楚了。</p><p>有些人，嘴上喊着兄弟朋友，遇事第一个和你划清界限。</p><p>这样的人，不适合成为朋友，也不要向他们求援。</p><p><img src="https://img.qxz5637.top/images/picgo/2025/05/21/20250521084705875.jpeg"></p><p><strong>2、嫌贫爱富的亲戚</strong></p><p>俗话说：<strong>穷在闹市无人问，富在深山有远亲。</strong></p><p>北宋有个叫吕蒙正的状元，年幼时家境贫寒，很多亲友都不愿意与他们家往来。</p><p>后来父母相继去世，让本就贫寒的家庭更是雪上加霜。</p><p>之前还在接济他们家的亲友看到这般光景，也都拒绝继续救助，生怕他欠钱不还。</p><p>年幼的吕蒙正，为了活下去，曾几次寻求亲戚的帮助，并承诺日后发达定会重礼答谢，但都被拒之门外。</p><p>为了活下去他上街乞讨，幸运的是没多久遇到一个好人，才得以满足温饱并且可以读书。</p><p>寒窗苦读数十载后，他最终金榜题名，名扬天下。</p><p>曾经那些避他如蛇蝎的亲戚，这时却都上门巴结。</p><p>世态炎凉，哪怕是拥有血缘关系的人，也会嫌贫爱富。</p><p>在他们看来，亲情捆绑着利益。所谓血缘，只是用得着的社会关系。</p><p>对有钱有势的人巴结奉承，对穷困潦倒的人冷嘲热讽。</p><p><strong>当你受穷受难时，与其指望亲戚雪中送炭，不如提升自己，好好赚钱。</strong></p><p>原文链接：<a href="https://www.msn.cn/zh-cn/news/other/%E6%9C%89%E9%92%B1%E4%B8%8D%E5%8E%BB%E4%B8%A4%E5%9C%B0-%E6%B2%A1%E9%92%B1%E4%B8%8D%E6%B1%82%E4%B8%A4%E4%BA%BA-%E8%80%81%E7%A5%96%E5%AE%97%E7%9A%84%E5%BF%A0%E5%91%8A-%E7%8E%B0%E5%AE%9E%E5%8F%88%E5%BF%83%E9%85%B8/ar-AA1F5VEV?ocid=msedgntp&amp;pc=CNNDDB&amp;cvid=43ccc52f1e424e059d8443570f4d78fd&amp;ei=73">“有钱不去两地，没钱不求两人”，老祖宗的忠告，现实又心酸！</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.qxz5637.top/images/picgo/2025/05/21/20250521084313921.jpeg&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;“有钱不去两地，没钱不求两人。”&quot;&gt;&lt;a href=&quot;#“有钱不去两地，没钱不求两人</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>画流程图、时序图(顺序图)、甘特图举例</title>
    <link href="https://www.qxz5637.top/2024/05/18/%E7%94%BB%E6%B5%81%E7%A8%8B%E5%9B%BE-%E6%97%B6%E5%BA%8F%E5%9B%BE(%E9%A1%BA%E5%BA%8F%E5%9B%BE)-%E7%94%98%E7%89%B9%E5%9B%BE/"/>
    <id>https://www.qxz5637.top/2024/05/18/%E7%94%BB%E6%B5%81%E7%A8%8B%E5%9B%BE-%E6%97%B6%E5%BA%8F%E5%9B%BE(%E9%A1%BA%E5%BA%8F%E5%9B%BE)-%E7%94%98%E7%89%B9%E5%9B%BE/</id>
    <published>2024-05-17T17:42:13.000Z</published>
    <updated>2025-05-22T11:20:54.866Z</updated>
    
    <content type="html"><![CDATA[<h5 id="网络收集的typora画流程图、时序图-顺序图-、甘特图，共8个实例，在Hexo上面没有效果"><a href="#网络收集的typora画流程图、时序图-顺序图-、甘特图，共8个实例，在Hexo上面没有效果" class="headerlink" title="网络收集的typora画流程图、时序图(顺序图)、甘特图，共8个实例，在Hexo上面没有效果"></a>网络收集的<code>typora画流程图、时序图(顺序图)、甘特图</code>，共8个实例，在<code>Hexo</code>上面没有效果</h5><span id="more"></span><ol><li>横向流程图源码格式：</li></ol><pre><code class=" mermaid">graph LRA[方形] --&gt;B(圆角)    B --&gt; C{条件a}    C --&gt;|a=1| D[结果1]    C --&gt;|a=2| E[结果2]    F[横向流程图]</code></pre><ol start="2"><li>竖向流程图源码格式：</li></ol><pre><code class=" mermaid">graph TDA[方形] --&gt; B(圆角)    B --&gt; C{条件a}    C --&gt; |a=1| D[结果1]    C --&gt; |a=2| E[结果2]    F[竖向流程图]</code></pre><ol start="3"><li>标准流程图源码格式：</li></ol><figure class="highlight plaintext"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs flow">st=&gt;start: 开始框<br>op=&gt;operation: 处理框<br>cond=&gt;condition: 判断框(是或否?)<br>sub1=&gt;subroutine: 子流程<br>io=&gt;inputoutput: 输入输出框<br>e=&gt;end: 结束框<br>st-&gt;op-&gt;cond<br>cond(yes)-&gt;io-&gt;e<br>cond(no)-&gt;sub1(right)-&gt;op<br></code></pre></td></tr></tbody></table></figure><ol start="4"><li>标准流程图源码格式（横向）：</li></ol><figure class="highlight plaintext"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs flow">st=&gt;start: 开始框<br>op=&gt;operation: 处理框<br>cond=&gt;condition: 判断框(是或否?)<br>sub1=&gt;subroutine: 子流程<br>io=&gt;inputoutput: 输入输出框<br>e=&gt;end: 结束框<br>st(right)-&gt;op(right)-&gt;cond<br>cond(yes)-&gt;io(bottom)-&gt;e<br>cond(no)-&gt;sub1(right)-&gt;op<br></code></pre></td></tr></tbody></table></figure><ol start="5"><li>UML时序图源码样例：</li></ol><figure class="highlight plaintext"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs sequence">对象A-&gt;对象B: 对象B你好吗?（请求）<br>Note right of 对象B: 对象B的描述<br>Note left of 对象A: 对象A的描述(提示)<br>对象B--&gt;对象A: 我很好(响应)<br>对象A-&gt;对象B: 你真的好吗？<br></code></pre></td></tr></tbody></table></figure><ol start="6"><li>UML时序图源码复杂样例：</li></ol><figure class="highlight plaintext"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs sequence">Title: 标题：复杂使用<br>对象A-&gt;对象B: 对象B你好吗?（请求）<br>Note right of 对象B: 对象B的描述<br>Note left of 对象A: 对象A的描述(提示)<br>对象B--&gt;对象A: 我很好(响应)<br>对象B-&gt;小三: 你好吗<br>小三--&gt;&gt;对象A: 对象B找我了<br>对象A-&gt;对象B: 你真的好吗？<br>Note over 小三,对象B: 我们是朋友<br>participant C<br>Note right of C: 没人陪我玩<br></code></pre></td></tr></tbody></table></figure><ol start="7"><li>UML标准时序图样例：</li></ol><pre><code class=" mermaid">%% 时序图例子,-&gt; 直线，--&gt;虚线，-&gt;&gt;实线箭头  sequenceDiagram    participant 张三    participant 李四    张三-&gt;王五: 王五你好吗？    loop 健康检查        王五-&gt;王五: 与疾病战斗    end    Note right of 王五: 合理 食物 &lt;br/&gt;看医生...    李四--&gt;&gt;张三: 很好!    王五-&gt;李四: 你怎么样?    李四--&gt;王五: 很好!</code></pre><ol start="8"><li>甘特图样例：</li></ol><pre><code class=" mermaid">%% 语法示例        gantt        dateFormat  YYYY-MM-DD        title 软件开发甘特图        section 设计        需求                      :done,    des1, 2014-01-06,2014-01-08        原型                      :active,  des2, 2014-01-09, 3d        UI设计                     :         des3, after des2, 5d    未来任务                     :         des4, after des3, 5d        section 开发        学习准备理解需求                      :crit, done, 2014-01-06,24h        设计框架                             :crit, done, after des2, 2d        开发                                 :crit, active, 3d        未来任务                              :crit, 5d        耍                                   :2d        section 测试        功能测试                              :active, a1, after des3, 3d        压力测试                               :after a1  , 20h        测试报告                               : 48h</code></pre><h5 id="效果图如下："><a href="#效果图如下：" class="headerlink" title="效果图如下："></a>效果图如下：</h5><p><img src="https://img.qxz5637.top/images/picgo/20250518151542140.png" alt="效果图"></p>]]></content>
    
    
    <summary type="html">&lt;h5 id=&quot;网络收集的typora画流程图、时序图-顺序图-、甘特图，共8个实例，在Hexo上面没有效果&quot;&gt;&lt;a href=&quot;#网络收集的typora画流程图、时序图-顺序图-、甘特图，共8个实例，在Hexo上面没有效果&quot; class=&quot;headerlink&quot; title=&quot;网络收集的typora画流程图、时序图(顺序图)、甘特图，共8个实例，在Hexo上面没有效果&quot;&gt;&lt;/a&gt;网络收集的&lt;code&gt;typora画流程图、时序图(顺序图)、甘特图&lt;/code&gt;，共8个实例，在&lt;code&gt;Hexo&lt;/code&gt;上面没有效果&lt;/h5&gt;</summary>
    
    
    
    <category term="学习" scheme="https://www.qxz5637.top/categories/%E5%AD%A6%E4%B9%A0/"/>
    
    
    <category term="学习" scheme="https://www.qxz5637.top/tags/%E5%AD%A6%E4%B9%A0/"/>
    
  </entry>
  
  <entry>
    <title>Docker常用命令</title>
    <link href="https://www.qxz5637.top/2024/05/18/Docker%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/"/>
    <id>https://www.qxz5637.top/2024/05/18/Docker%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/</id>
    <published>2024-05-17T16:06:35.000Z</published>
    <updated>2025-05-18T07:18:26.943Z</updated>
    
    <content type="html"><![CDATA[<h5 id="近期操作Docker经常用到的命令，记录一下。"><a href="#近期操作Docker经常用到的命令，记录一下。" class="headerlink" title="近期操作Docker经常用到的命令，记录一下。"></a>近期操作Docker经常用到的命令，记录一下。</h5><ol><li>root登陆Docker容器</li></ol><figure class="highlight xquery"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xquery">docker exec -u<span class="hljs-built_in"> root</span> -it <span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">container_id_or_name</span>&gt;</span> bash</span><br></code></pre></td></tr></tbody></table></figure><span id="more"></span><ol start="2"><li>退出docker容器,<code>Ctrl-D</code>或者在容器内输入</li></ol><figure class="highlight awk"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs awk"><span class="hljs-keyword">exit</span><br></code></pre></td></tr></tbody></table></figure><ol start="3"><li>慢慢补充<br><img src="https://img.qxz5637.top/images/picgo/20250518151724900.jpg" alt="Philadelphia's Magic Gardens. This place was so cool!" title="Philadelphia's Magic Gardens"></li></ol>]]></content>
    
    
    <summary type="html">&lt;h5 id=&quot;近期操作Docker经常用到的命令，记录一下。&quot;&gt;&lt;a href=&quot;#近期操作Docker经常用到的命令，记录一下。&quot; class=&quot;headerlink&quot; title=&quot;近期操作Docker经常用到的命令，记录一下。&quot;&gt;&lt;/a&gt;近期操作Docker经常用到的命令，记录一下。&lt;/h5&gt;&lt;ol&gt;
&lt;li&gt;root登陆Docker容器&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class=&quot;highlight xquery&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;code class=&quot;hljs xquery&quot;&gt;docker exec -u&lt;span class=&quot;hljs-built_in&quot;&gt; root&lt;/span&gt; -it &lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;container_id_or_name&lt;/span&gt;&amp;gt;&lt;/span&gt; bash&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>使用key免密rsync同步</title>
    <link href="https://www.qxz5637.top/2024/05/16/%E4%BD%BF%E7%94%A8key%E5%85%8D%E5%AF%86rsync%E5%90%8C%E6%AD%A5/"/>
    <id>https://www.qxz5637.top/2024/05/16/%E4%BD%BF%E7%94%A8key%E5%85%8D%E5%AF%86rsync%E5%90%8C%E6%AD%A5/</id>
    <published>2024-05-16T00:46:53.000Z</published>
    <updated>2024-05-16T08:54:44.969Z</updated>
    
    <content type="html"><![CDATA[<h5 id="这个rsync命令使用SSH以指定的私钥和端口号，同步远程服务器上114-132-51-2IP的test目录（在xujc用户下）。"><a href="#这个rsync命令使用SSH以指定的私钥和端口号，同步远程服务器上114-132-51-2IP的test目录（在xujc用户下）。" class="headerlink" title="这个rsync命令使用SSH以指定的私钥和端口号，同步远程服务器上114.132.51.2IP的test目录（在xujc用户下）。"></a>这个<code>rsync</code>命令使用SSH以指定的私钥和端口号，同步远程服务器上<code>114.132.51.2</code>IP的<code>test</code>目录（在<code>xujc</code>用户下）。</h5><h6 id="文件的内容会被复制到本地的test2目录中，同时保留了元数据和权限。-v选项显示同步过程的详细信息。"><a href="#文件的内容会被复制到本地的test2目录中，同时保留了元数据和权限。-v选项显示同步过程的详细信息。" class="headerlink" title="文件的内容会被复制到本地的test2目录中，同时保留了元数据和权限。-v选项显示同步过程的详细信息。"></a>文件的内容会被复制到本地的<code>test2</code>目录中，同时保留了元数据和权限。<code>-v</code>选项显示同步过程的详细信息。</h6><span id="more"></span><figure class="highlight ruby"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs ruby">ssh-copy-id -i ~<span class="hljs-regexp">/.ssh/my</span>_ssh_key.pub -p <span class="hljs-number">30024</span> xujc<span class="hljs-variable">@114</span>.<span class="hljs-number">132.51</span>.<span class="hljs-number">2</span><br>rsync -av -e <span class="hljs-string">"ssh -i .ssh/my_ssh_key -p 30024"</span> xujc<span class="hljs-variable">@114</span>.<span class="hljs-number">132.51</span>.<span class="hljs-number">2</span><span class="hljs-symbol">:test</span> test2<br></code></pre></td></tr></tbody></table></figure><h5 id="其他同步方式同理"><a href="#其他同步方式同理" class="headerlink" title="其他同步方式同理"></a>其他同步方式同理</h5><h5 id="进入ssh目录，当前目录是-home-hexo-ssh"><a href="#进入ssh目录，当前目录是-home-hexo-ssh" class="headerlink" title="进入ssh目录，当前目录是/home/hexo/.ssh"></a>进入<code>ssh</code>目录，当前目录是<code>/home/hexo/.ssh</code></h5><figure class="highlight ruby"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs ruby">scp id_rsa.pub root<span class="hljs-variable">@139</span>.<span class="hljs-number">224.18</span>.<span class="hljs-number">107</span><span class="hljs-symbol">:/root/</span>.ssh<br>ssh-copy-id -i ~<span class="hljs-regexp">/.ssh/id</span>_rsa.pub root<span class="hljs-variable">@139</span>.<span class="hljs-number">224.18</span>.<span class="hljs-number">107</span><br></code></pre></td></tr></tbody></table></figure><h5 id="下面是本人在用的同步命令"><a href="#下面是本人在用的同步命令" class="headerlink" title="下面是本人在用的同步命令"></a>下面是本人在用的同步命令</h5><figure class="highlight ruby"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ruby">rsync -avz -e <span class="hljs-string">"ssh -i ~/.ssh/id_rsa"</span> /home/hexo/.hexo/<span class="hljs-keyword">public</span> root<span class="hljs-variable">@0</span>.<span class="hljs-number">0.0</span>.<span class="hljs-number">0</span><span class="hljs-symbol">:/usr/local/src</span><br></code></pre></td></tr></tbody></table></figure><h5 id="编写脚本"><a href="#编写脚本" class="headerlink" title="编写脚本"></a>编写脚本</h5><figure class="highlight ruby"><table><tbody><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><code class="hljs ruby">[root<span class="hljs-variable">@node1</span> ~]<span class="hljs-comment"># cat rsync.sh </span><br><span class="hljs-comment">#!/bin/bash</span><br>rsync -avz root<span class="hljs-variable">@192</span>.<span class="hljs-number">168.110</span>.<span class="hljs-number">13</span><span class="hljs-symbol">:/var/log/messages</span> /rsync/messages.<span class="hljs-string">`date +%y%m%d-%H%M`</span><br></code></pre></td></tr></tbody></table></figure><h5 id="计划定时任务：每天00：10分执行脚本，记录日志"><a href="#计划定时任务：每天00：10分执行脚本，记录日志" class="headerlink" title="计划定时任务：每天00：10分执行脚本，记录日志"></a>计划定时任务：每天00：10分执行脚本，记录日志</h5><figure class="highlight autoit"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs autoit">[root<span class="hljs-symbol">@node1</span> ~]<span class="hljs-meta"># crontab -l</span><br><span class="hljs-number">10</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> * * bash rsync.sh<br></code></pre></td></tr></tbody></table></figure>]]></content>
    
    
    <summary type="html">&lt;h5 id=&quot;这个rsync命令使用SSH以指定的私钥和端口号，同步远程服务器上114-132-51-2IP的test目录（在xujc用户下）。&quot;&gt;&lt;a href=&quot;#这个rsync命令使用SSH以指定的私钥和端口号，同步远程服务器上114-132-51-2IP的test目录（在xujc用户下）。&quot; class=&quot;headerlink&quot; title=&quot;这个rsync命令使用SSH以指定的私钥和端口号，同步远程服务器上114.132.51.2IP的test目录（在xujc用户下）。&quot;&gt;&lt;/a&gt;这个&lt;code&gt;rsync&lt;/code&gt;命令使用SSH以指定的私钥和端口号，同步远程服务器上&lt;code&gt;114.132.51.2&lt;/code&gt;IP的&lt;code&gt;test&lt;/code&gt;目录（在&lt;code&gt;xujc&lt;/code&gt;用户下）。&lt;/h5&gt;&lt;h6 id=&quot;文件的内容会被复制到本地的test2目录中，同时保留了元数据和权限。-v选项显示同步过程的详细信息。&quot;&gt;&lt;a href=&quot;#文件的内容会被复制到本地的test2目录中，同时保留了元数据和权限。-v选项显示同步过程的详细信息。&quot; class=&quot;headerlink&quot; title=&quot;文件的内容会被复制到本地的test2目录中，同时保留了元数据和权限。-v选项显示同步过程的详细信息。&quot;&gt;&lt;/a&gt;文件的内容会被复制到本地的&lt;code&gt;test2&lt;/code&gt;目录中，同时保留了元数据和权限。&lt;code&gt;-v&lt;/code&gt;选项显示同步过程的详细信息。&lt;/h6&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Docker利用busybox创建基础镜像</title>
    <link href="https://www.qxz5637.top/2024/05/14/Docker%E5%88%A9%E7%94%A8busybox%E5%88%9B%E5%BB%BA%E5%9F%BA%E7%A1%80%E9%95%9C%E5%83%8F/"/>
    <id>https://www.qxz5637.top/2024/05/14/Docker%E5%88%A9%E7%94%A8busybox%E5%88%9B%E5%BB%BA%E5%9F%BA%E7%A1%80%E9%95%9C%E5%83%8F/</id>
    <published>2024-05-14T05:35:26.000Z</published>
    <updated>2024-05-14T14:25:43.662Z</updated>
    
    <content type="html"><![CDATA[<h5 id="今天小编就为大家分享一篇关于Docker利用busybox创建基础镜像-base-image-，小编觉得内容挺不错的，现在分享给大家，具有很好的参考价值，需要的朋友一起跟随小编来看看吧"><a href="#今天小编就为大家分享一篇关于Docker利用busybox创建基础镜像-base-image-，小编觉得内容挺不错的，现在分享给大家，具有很好的参考价值，需要的朋友一起跟随小编来看看吧" class="headerlink" title="今天小编就为大家分享一篇关于Docker利用busybox创建基础镜像(base image)，小编觉得内容挺不错的，现在分享给大家，具有很好的参考价值，需要的朋友一起跟随小编来看看吧"></a>今天小编就为大家分享一篇关于<code>Docker</code>利用<code>busybox</code>创建基础镜像(<code>base image</code>)，小编觉得内容挺不错的，现在分享给大家，具有很好的参考价值，需要的朋友一起跟随小编来看看吧</h5><h5 id="docker镜像的首行从FROM-alpine之类的镜像开始，但是最初的基础镜像是如何创建的，本文使用一个busybox创建一个基础镜像，相信在此过程中会对docker一些相关的概念有进一步的理解。"><a href="#docker镜像的首行从FROM-alpine之类的镜像开始，但是最初的基础镜像是如何创建的，本文使用一个busybox创建一个基础镜像，相信在此过程中会对docker一些相关的概念有进一步的理解。" class="headerlink" title="docker镜像的首行从FROM alpine之类的镜像开始，但是最初的基础镜像是如何创建的，本文使用一个busybox创建一个基础镜像，相信在此过程中会对docker一些相关的概念有进一步的理解。"></a><code>docker</code>镜像的首行从<code>FROM alpine</code>之类的镜像开始，但是最初的基础镜像是如何创建的，本文使用一个<code>busybox</code>创建一个基础镜像，相信在此过程中会对<code>docker</code>一些相关的概念有进一步的理解。</h5><span id="more"></span><h4 id="什么是基础镜像（base-image）"><a href="#什么是基础镜像（base-image）" class="headerlink" title="什么是基础镜像（base image）"></a>什么是基础镜像（<code>base image</code>）</h4><h5 id="简单来说，基础镜像就是没有From或者FROM-scratch开头的Dockerfile所构建出来的镜像。比如alpine，这个很小的linux镜像目前只有4M左右"><a href="#简单来说，基础镜像就是没有From或者FROM-scratch开头的Dockerfile所构建出来的镜像。比如alpine，这个很小的linux镜像目前只有4M左右" class="headerlink" title="简单来说，基础镜像就是没有From或者FROM scratch开头的Dockerfile所构建出来的镜像。比如alpine，这个很小的linux镜像目前只有4M左右"></a>简单来说，基础镜像就是没有From或者<code>FROM scratch</code>开头的<code>Dockerfile</code>所构建出来的镜像。比如<code>alpine</code>，这个很小的<code>linux</code>镜像目前只有4M左右</h5><figure class="highlight autoit"><table><tbody><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><code class="hljs autoit">[root<span class="hljs-symbol">@kong</span> ~]<span class="hljs-meta"># docker images |grep alpine</span><br>docker.io/alpine latest <span class="hljs-number">3</span>fd9065eaf02 <span class="hljs-number">4</span> months ago <span class="hljs-number">4.15</span> MB<br>[root<span class="hljs-symbol">@kong</span> ~]<span class="hljs-meta">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="它的Dockerfile很简单，只有三行，这就是一个基础镜像"><a href="#它的Dockerfile很简单，只有三行，这就是一个基础镜像" class="headerlink" title="它的Dockerfile很简单，只有三行，这就是一个基础镜像,"></a>它的Dockerfile很简单，只有三行，这就是一个基础镜像,</h5><figure class="highlight dockerfile"><table><tbody><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><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> scratch<br><span class="hljs-keyword">ADD</span><span class="language-bash"> rootfs.tar.xz /</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [“/bin/sh”]</span><br></code></pre></td></tr></tbody></table></figure><h5 id="在接下来的文章中我们将会像alpine那样来创建一个自己的基础镜像。"><a href="#在接下来的文章中我们将会像alpine那样来创建一个自己的基础镜像。" class="headerlink" title="在接下来的文章中我们将会像alpine那样来创建一个自己的基础镜像。"></a>在接下来的文章中我们将会像<code>alpine</code>那样来创建一个自己的基础镜像。</h5><h4 id="busybox"><a href="#busybox" class="headerlink" title="busybox"></a><code>busybox</code></h4><h5 id="概要说明"><a href="#概要说明" class="headerlink" title="概要说明"></a>概要说明</h5><h5 id="busybox被称为嵌入式linux的瑞士军刀，这句话是在busybox自己介绍自己的时候提出的-The-Swiss-Army-Knife-of-Embedded-Linux-。busybox整合了很多小的Unix下的通用功能到一个小的可执行文件之中，简单来说在unix或者linux下常用的那些功能在这里你都能找到，但是为了busybox的目标：嵌入式的linux，大小对于busybox来说是非常重要的优化要素和限制，这些功能有可能会有所阉割，但是对于一般需求来说已经足够。而alpine就是在busybox基础上增加了自己的包管理工具apk等功能创建了风靡一时的小巧镜像。busybox是用C语言开发的基于GPL的开源项目，目前的稳定版本为1-28-4。"><a href="#busybox被称为嵌入式linux的瑞士军刀，这句话是在busybox自己介绍自己的时候提出的-The-Swiss-Army-Knife-of-Embedded-Linux-。busybox整合了很多小的Unix下的通用功能到一个小的可执行文件之中，简单来说在unix或者linux下常用的那些功能在这里你都能找到，但是为了busybox的目标：嵌入式的linux，大小对于busybox来说是非常重要的优化要素和限制，这些功能有可能会有所阉割，但是对于一般需求来说已经足够。而alpine就是在busybox基础上增加了自己的包管理工具apk等功能创建了风靡一时的小巧镜像。busybox是用C语言开发的基于GPL的开源项目，目前的稳定版本为1-28-4。" class="headerlink" title="busybox被称为嵌入式linux的瑞士军刀，这句话是在busybox自己介绍自己的时候提出的(The Swiss Army Knife of Embedded Linux)。busybox整合了很多小的Unix下的通用功能到一个小的可执行文件之中，简单来说在unix或者linux下常用的那些功能在这里你都能找到，但是为了busybox的目标：嵌入式的linux，大小对于busybox来说是非常重要的优化要素和限制，这些功能有可能会有所阉割，但是对于一般需求来说已经足够。而alpine就是在busybox基础上增加了自己的包管理工具apk等功能创建了风靡一时的小巧镜像。busybox是用C语言开发的基于GPL的开源项目，目前的稳定版本为1.28.4。"></a><code>busybox</code>被称为嵌入式linux的瑞士军刀，这句话是在<code>busybox</code>自己介绍自己的时候提出的(<code>The Swiss Army Knife of Embedded Linux</code>)。<code>busybox</code>整合了很多小的<code>Unix</code>下的通用功能到一个小的可执行文件之中，简单来说在<code>unix</code>或者<code>linux</code>下常用的那些功能在这里你都能找到，但是为了<code>busybox</code>的目标：嵌入式的<code>linux</code>，大小对于<code>busybox</code>来说是非常重要的优化要素和限制，这些功能有可能会有所阉割，但是对于一般需求来说已经足够。而<code>alpine</code>就是在<code>busybox</code>基础上增加了自己的包管理工具<code>apk</code>等功能创建了风靡一时的小巧镜像。<code>busybox</code>是用<code>C</code>语言开发的基于<code>GPL</code>的开源项目，目前的稳定版本为<code>1.28.4</code>。</h5><h5 id="宿主机器"><a href="#宿主机器" class="headerlink" title="宿主机器"></a>宿主机器</h5><h5 id="下载busybox"><a href="#下载busybox" class="headerlink" title="下载busybox"></a>下载busybox</h5><figure class="highlight llvm"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs llvm">[root<span class="hljs-title">@kong</span> ~]# uname -a<br>Linux kong <span class="hljs-number">3.10</span>.<span class="hljs-number">0</span><span class="hljs-number">-693</span>.el<span class="hljs-number">7</span>.<span class="hljs-keyword">x</span><span class="hljs-number">86</span>_<span class="hljs-number">64</span> <span class="hljs-variable">#1</span> SMP Tue Aug <span class="hljs-number">22</span> <span class="hljs-number">21</span>:<span class="hljs-number">09</span>:<span class="hljs-number">27</span> UTC <span class="hljs-number">2017</span> <span class="hljs-keyword">x</span><span class="hljs-number">86</span>_<span class="hljs-number">64</span> <span class="hljs-keyword">x</span><span class="hljs-number">86</span>_<span class="hljs-number">64</span> <span class="hljs-keyword">x</span><span class="hljs-number">86</span>_<span class="hljs-number">64</span> GNU/Linux<br>[root<span class="hljs-title">@kong</span> ~]# cat /etc/RedHat-<span class="hljs-keyword">release</span><br>Centos Linux <span class="hljs-keyword">release</span> <span class="hljs-number">7.4</span>.<span class="hljs-number">1708</span> (Core)<br>[root<span class="hljs-title">@kong</span> ~]#<br></code></pre></td></tr></tbody></table></figure><h5 id="简单可以直接使用的二进制最新的版本为1-28-1"><a href="#简单可以直接使用的二进制最新的版本为1-28-1" class="headerlink" title="简单可以直接使用的二进制最新的版本为1.28.1"></a>简单可以直接使用的二进制最新的版本为<code>1.28.1</code></h5><figure class="highlight crystal"><table><tbody><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><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs crystal">[root<span class="hljs-variable">@kong</span> ~]<span class="hljs-comment"># wget https://busybox.net/downloads/binaries/1.28.1-defconfig-multiarch/busybox-x86_64</span><br>–<span class="hljs-number">2018</span>-<span class="hljs-number">0</span>5-<span class="hljs-number">25</span> <span class="hljs-number">0</span>4:<span class="hljs-number">51</span>:<span class="hljs-number">20</span>– <span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/busybox.net/downloads</span><span class="hljs-regexp">/binaries/</span><span class="hljs-number">1.28</span>.<span class="hljs-number">1</span>-defconfig-multiarch/busybox-x86_64<br>Resolving busybox.net (busybox.net)… <span class="hljs-number">140.211</span>.<span class="hljs-number">167.122</span><br>Connecting to busybox.net (busybox.net)|<span class="hljs-number">140.211</span>.<span class="hljs-number">167.122</span>|:<span class="hljs-number">443</span>… connected.<br>HTTP request sent, awaiting response… <span class="hljs-number">200</span> OK<br><span class="hljs-symbol">Length:</span> <span class="hljs-number">1001112</span> (<span class="hljs-number">978</span>K)<br>Saving <span class="hljs-symbol">to:</span> ‘busybox-x86_64’<br><span class="hljs-number">100</span><span class="hljs-string">%[==============================================================================================&gt;]</span> <span class="hljs-number">1</span>,<span class="hljs-number">0</span>01,<span class="hljs-number">112</span> <span class="hljs-number">19.3</span>KB/s in <span class="hljs-number">30</span>s<br><span class="hljs-number">2018</span>-<span class="hljs-number">0</span>5-<span class="hljs-number">25</span> <span class="hljs-number">0</span>4:<span class="hljs-number">51</span>:<span class="hljs-number">57</span> (<span class="hljs-number">32.4</span> KB/s) – ‘busybox-x86_64’ saved [<span class="hljs-number">1001112</span>/<span class="hljs-number">1001112</span>]<br>[root<span class="hljs-variable">@kong</span> ~]<span class="hljs-comment">#</span><br>设定busybox<br><br>[root<span class="hljs-variable">@kong</span> ~]<span class="hljs-comment"># cp busybox-x86_64 /usr/local/bin/busybox</span><br>[root<span class="hljs-variable">@kong</span> ~]<span class="hljs-comment"># chmod +x /usr/local/bin/busybox</span><br>[root<span class="hljs-variable">@kong</span> ~]<span class="hljs-comment"># which busybox</span><br><span class="hljs-regexp">/usr/local</span><span class="hljs-regexp">/bin/busybox</span><br>[root<span class="hljs-variable">@kong</span> ~]<span class="hljs-comment">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="版本确认"><a href="#版本确认" class="headerlink" title="版本确认"></a>版本确认</h5><h5 id="输入busybox可以看出版本以及熟悉的linux下的工具，仔细看一遍就会理解busybox号称自己是瑞士军刀一点都不夸张，反过来说，瑞士军刀如果敢号称linux里的busybox可能会引起非议。"><a href="#输入busybox可以看出版本以及熟悉的linux下的工具，仔细看一遍就会理解busybox号称自己是瑞士军刀一点都不夸张，反过来说，瑞士军刀如果敢号称linux里的busybox可能会引起非议。" class="headerlink" title="输入busybox可以看出版本以及熟悉的linux下的工具，仔细看一遍就会理解busybox号称自己是瑞士军刀一点都不夸张，反过来说，瑞士军刀如果敢号称linux里的busybox可能会引起非议。"></a>输入<code>busybox</code>可以看出版本以及熟悉的<code>linux</code>下的工具，仔细看一遍就会理解<code>busybox</code>号称自己是瑞士军刀一点都不夸张，反过来说，瑞士军刀如果敢号称<code>linux</code>里的<code>busybox</code>可能会引起非议。</h5><figure class="highlight bash"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><code class="hljs bash">[root@kong ~]# busybox<br>BusyBox v1.28.1 (2018-02-15 14:34:02 CET) multi-call binary.<br>BusyBox is copyrighted by many authors between 1998-2015.<br>Licensed under GPLv2. See <span class="hljs-built_in">source</span> distribution <span class="hljs-keyword">for</span> detailed<br>copyright notices.<br>Usage: busybox [<span class="hljs-keyword">function</span> [arguments]…]<br>     or: busybox –list[-full]<br>     or: busybox –install [-s] [DIR]<br>     or: <span class="hljs-keyword">function</span> [arguments]…<br>     BusyBox is a multi-call binary that combines many common Unix<br>     utilities into a single executable. Most people will create a<br>     <span class="hljs-built_in">link</span> to busybox <span class="hljs-keyword">for</span> each <span class="hljs-keyword">function</span> they wish to use and BusyBox<br>     will act like whatever it was invoked as.<br>Currently defined <span class="hljs-built_in">functions</span>:<br>     [, [[, acpid, add-shell, addgroup, adduser, adjtimex, <span class="hljs-built_in">arch</span>, arp, arping, ash, awk, <span class="hljs-built_in">base64</span>, <span class="hljs-built_in">basename</span>, beep, blkdiscard, blkid,<br>     blockdev, bootchartd, brctl, bunzip2, bzcat, bzip2, cal, <span class="hljs-built_in">cat</span>, chat, chattr, <span class="hljs-built_in">chgrp</span>, <span class="hljs-built_in">chmod</span>, <span class="hljs-built_in">chown</span>, chpasswd, chpst, <span class="hljs-built_in">chroot</span>, chrt,<br>     chvt, <span class="hljs-built_in">cksum</span>, clear, cmp, <span class="hljs-built_in">comm</span>, conspy, <span class="hljs-built_in">cp</span>, cpio, crond, crontab, cryptpw, cttyhack, <span class="hljs-built_in">cut</span>, <span class="hljs-built_in">date</span>, dc, <span class="hljs-built_in">dd</span>, deallocvt, delgroup,<br>     deluser, depmod, devmem, <span class="hljs-built_in">df</span>, dhcprelay, diff, <span class="hljs-built_in">dirname</span>, dmesg, dnsd, dnsdomainname, DOS2unix, dpkg, dpkg-deb, <span class="hljs-built_in">du</span>, dumpkmap,<br>     dumpleases, <span class="hljs-built_in">echo</span>, ed, egrep, eject, <span class="hljs-built_in">env</span>, envdir, envuidgid, ether-wake, <span class="hljs-built_in">expand</span>, <span class="hljs-built_in">expr</span>, <span class="hljs-built_in">factor</span>, fakeidentd, fallocate, <span class="hljs-literal">false</span>,<br>     fatattr, fbset, fbsplash, fdflush, fdformat, fdisk, fgconsole, fgrep, find, findfs, flock, <span class="hljs-built_in">fold</span>, free, freeramdisk, fsck,<br>     fsck.minix, fsfreeze, fstrim, fsync, ftpd, ftpget, ftpput, fuser, getopt, getty, grep, <span class="hljs-built_in">groups</span>, gunzip, gzip, halt, hd, hdparm,<br>     <span class="hljs-built_in">head</span>, hexdump, hexedit, <span class="hljs-built_in">hostid</span>, hostname, httpd, hush, hwclock, i2cdetect, i2cdump, i2cget, i2cset, <span class="hljs-built_in">id</span>, ifconfig, ifdown,<br>     ifenslave, ifplugd, ifup, inetd, init, insmod, install, ionice, IOStat, ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, ipneigh,<br>     iproute, iprule, iptunnel, kbd_mode, <span class="hljs-built_in">kill</span>, killall, killall5, klogd, last, less, <span class="hljs-built_in">link</span>, linux32, linux64, linuxrc, <span class="hljs-built_in">ln</span>, loadfont,<br>     loadkmap, logger, login, <span class="hljs-built_in">logname</span>, logread, losetup, lpd, lpq, lpr, <span class="hljs-built_in">ls</span>, lsattr, lsmod, lsof, lspci, lsscsi, lsusb, lzcat, lzma,<br>     lzop, makedevs, makemime, man, <span class="hljs-built_in">md5sum</span>, mdev, mesg, microcom, <span class="hljs-built_in">mkdir</span>, mkdosfs, mke2fs, <span class="hljs-built_in">mkfifo</span>, mkfs.ext2, mkfs.minix, mkfs.vfat,<br>     <span class="hljs-built_in">mknod</span>, mkpasswd, mkswap, <span class="hljs-built_in">mktemp</span>, modinfo, modprobe, more, mount, mountpoint, mpstat, mt, <span class="hljs-built_in">mv</span>, nameif, nanddump, nandwrite,<br>     nbd-client, nc, netstat, <span class="hljs-built_in">nice</span>, <span class="hljs-built_in">nl</span>, nmeter, <span class="hljs-built_in">nohup</span>, <span class="hljs-built_in">nproc</span>, nsenter, nslookup, ntpd, nuke, <span class="hljs-built_in">od</span>, openvt, partprobe, passwd, <span class="hljs-built_in">paste</span>,<br>     patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill, pmap, popmaildir, poweroff, powertop, <span class="hljs-built_in">printenv</span>, <span class="hljs-built_in">printf</span>, ps,<br>     pscan, pstree, <span class="hljs-built_in">pwd</span>, pwdx, raidautorun, rdate, rdev, readahead, <span class="hljs-built_in">readlink</span>, readprofile, <span class="hljs-built_in">realpath</span>, reboot, reformime,<br>     remove-shell, renice, reset, resize, resume, rev, <span class="hljs-built_in">rm</span>, <span class="hljs-built_in">rmdir</span>, rmmod, route, rpm, rpm2cpio, rtcwake, run-init, run-parts,<br>     runlevel, runsv, runsvdir, rx, script, scriptreplay, sed, sendmail, <span class="hljs-built_in">seq</span>, setarch, setconsole, setfattr, setfont, setkeycodes,<br>     setlogcons, setpriv, setserial, setsid, setuidgid, sh, <span class="hljs-built_in">sha1sum</span>, <span class="hljs-built_in">sha256sum</span>, sha3sum, <span class="hljs-built_in">sha512sum</span>, showkey, <span class="hljs-built_in">shred</span>, <span class="hljs-built_in">shuf</span>, slattach,<br>     <span class="hljs-built_in">sleep</span>, smemcap, softlimit, <span class="hljs-built_in">sort</span>, <span class="hljs-built_in">split</span>, ssl_client, start-stop-daemon, <span class="hljs-built_in">stat</span>, strings, <span class="hljs-built_in">stty</span>, su, sulogin, <span class="hljs-built_in">sum</span>, sv, svc, svlogd,<br>     swapoff, swapon, switch_root, <span class="hljs-built_in">sync</span>, sysctl, syslogd, <span class="hljs-built_in">tac</span>, <span class="hljs-built_in">tail</span>, tar, taskset, tcpsvd, <span class="hljs-built_in">tee</span>, telnet, telnetd, <span class="hljs-built_in">test</span>, tftp, tftpd,<br>     <span class="hljs-keyword">time</span>, <span class="hljs-built_in">timeout</span>, top, <span class="hljs-built_in">touch</span>, <span class="hljs-built_in">tr</span>, traceroute, traceroute6, <span class="hljs-literal">true</span>, <span class="hljs-built_in">truncate</span>, <span class="hljs-built_in">tty</span>, ttysize, tunctl, ubiattach, ubidetach, ubimkvol,<br>     ubirename, ubirmvol, ubirsvol, ubiupdatevol, udhcpc, udhcpd, udpsvd, uevent, umount, <span class="hljs-built_in">uname</span>, <span class="hljs-built_in">unexpand</span>, <span class="hljs-built_in">uniq</span>, unix2dos, <span class="hljs-built_in">unlink</span>,<br>     unlzma, unshare, unxz, unzip, <span class="hljs-built_in">uptime</span>, <span class="hljs-built_in">users</span>, usleep, uudecode, uuencode, vconfig, vi, vlock, volname, w, wall, watch, watchdog,<br>     <span class="hljs-built_in">wc</span>, wget, <span class="hljs-built_in">which</span>, <span class="hljs-built_in">who</span>, <span class="hljs-built_in">whoami</span>, whois, xargs, xxd, xz, xzcat, <span class="hljs-built_in">yes</span>, zcat, zcip<br>[root@kong ~]<br></code></pre></td></tr></tbody></table></figure><h5 id="创建rootfs"><a href="#创建rootfs" class="headerlink" title="创建rootfs"></a>创建<code>rootfs</code></h5><h5 id="这张图在镜像基础介绍的时候已经被无数次看到了，rootfs是linux中重要的概念，而alpine中也有ADD-rootfs-tar-xz这样一句，接下来我们将了解一下如何生成一个简单的rootfs"><a href="#这张图在镜像基础介绍的时候已经被无数次看到了，rootfs是linux中重要的概念，而alpine中也有ADD-rootfs-tar-xz这样一句，接下来我们将了解一下如何生成一个简单的rootfs" class="headerlink" title="这张图在镜像基础介绍的时候已经被无数次看到了，rootfs是linux中重要的概念，而alpine中也有ADD rootfs.tar.xz这样一句，接下来我们将了解一下如何生成一个简单的rootfs"></a>这张图在镜像基础介绍的时候已经被无数次看到了，<code>rootfs</code>是<code>linux</code>中重要的概念，而<code>alpine</code>中也有<code>ADD rootfs.tar.xz</code>这样一句，接下来我们将了解一下如何生成一个简单的<code>rootfs</code></h5><h5 id="创建目录并进入"><a href="#创建目录并进入" class="headerlink" title="创建目录并进入"></a>创建目录并进入</h5><figure class="highlight autoit"><table><tbody><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><code class="hljs autoit">[root<span class="hljs-symbol">@kong</span> ~]<span class="hljs-meta"># mkdir rootfs</span><br>[root<span class="hljs-symbol">@kong</span> ~]<span class="hljs-meta"># cd rootfs/</span><br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="创建rootfs-1"><a href="#创建rootfs-1" class="headerlink" title="创建rootfs"></a>创建<code>rootfs</code></h5><h5 id="执行如下语句"><a href="#执行如下语句" class="headerlink" title="执行如下语句"></a>执行如下语句</h5><figure class="highlight dsconfig"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs dsconfig"><span class="hljs-string">for</span> <span class="hljs-string">module</span> <span class="hljs-string">in</span> `<span class="hljs-string">busybox</span> –<span class="hljs-built_in">list-modules`</span><br><span class="hljs-string">do</span><br>     <span class="hljs-string">mkdir</span> -<span class="hljs-string">p</span> `<span class="hljs-string">dirname</span> “$<span class="hljs-string">module</span>”`<br>     <span class="hljs-string">ln</span> -<span class="hljs-string">sf</span> /<span class="hljs-string">bin</span>/<span class="hljs-string">busybox</span> “$<span class="hljs-string">module</span>”<br><span class="hljs-string">done</span><br></code></pre></td></tr></tbody></table></figure><h5 id="执行日志"><a href="#执行日志" class="headerlink" title="执行日志"></a>执行日志</h5><figure class="highlight shell"><table><tbody><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><code class="hljs shell">[root@kong rootfs]# for module in `busybox –list-modules`<br><span class="hljs-meta prompt_">&gt; </span><span class="language-bash"><span class="hljs-keyword">do</span></span><br><span class="hljs-meta prompt_">&gt; </span><span class="language-bash"><span class="hljs-built_in">mkdir</span> -p `<span class="hljs-built_in">dirname</span> “<span class="hljs-variable">$module</span>”`</span><br><span class="hljs-meta prompt_">&gt; </span><span class="language-bash"><span class="hljs-built_in">ln</span> -sf /bin/busybox “<span class="hljs-variable">$module</span>”</span><br><span class="hljs-meta prompt_">&gt; </span><span class="language-bash"><span class="hljs-keyword">done</span></span><br>[root@kong rootfs]#<br></code></pre></td></tr></tbody></table></figure><h5 id="结果确认"><a href="#结果确认" class="headerlink" title="结果确认"></a>结果确认</h5><figure class="highlight jboss-cli"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs jboss-cli">[root@kong rootfs]<span class="hljs-comment"># ls</span><br>bin linuxrc sbin usr<br>[root@kong rootfs]<span class="hljs-comment"># find . -type d</span><br>.<br><span class="hljs-string">./usr</span><br><span class="hljs-string">./usr/bin</span><br><span class="hljs-string">./usr/sbin</span><br><span class="hljs-string">./sbin</span><br><span class="hljs-string">./bin</span><br>[root@kong rootfs]<span class="hljs-comment">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="将busybox拷贝至新创建的-bin目录下"><a href="#将busybox拷贝至新创建的-bin目录下" class="headerlink" title="将busybox拷贝至新创建的./bin目录下"></a>将<code>busybox</code>拷贝至新创建的<code>./bin</code>目录下</h5><h5 id="这样，上述命令的链接对象就存在了"><a href="#这样，上述命令的链接对象就存在了" class="headerlink" title="这样，上述命令的链接对象就存在了"></a>这样，上述命令的链接对象就存在了</h5><figure class="highlight autoit"><table><tbody><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><code class="hljs autoit">[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># cp /usr/local/bin/busybox bin/</span><br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># ls -l bin/busybox</span><br>-rwxr-xr-x. <span class="hljs-number">1</span> root root <span class="hljs-number">1001112</span> May <span class="hljs-number">25</span> <span class="hljs-number">05</span>:<span class="hljs-number">27</span> bin/busybox<br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="创建rootfs-tar"><a href="#创建rootfs-tar" class="headerlink" title="创建rootfs.tar"></a>创建<code>rootfs.tar</code></h5><h5 id="此处注意相对路径，而后续次相对路径会展开至-下，从而创建新的系统的rootfs，这也是从零搭建linux-linux-from-scratch-的重要操作之一。"><a href="#此处注意相对路径，而后续次相对路径会展开至-下，从而创建新的系统的rootfs，这也是从零搭建linux-linux-from-scratch-的重要操作之一。" class="headerlink" title="此处注意相对路径，而后续次相对路径会展开至/下，从而创建新的系统的rootfs，这也是从零搭建linux(linux from scratch)的重要操作之一。"></a>此处注意相对路径，而后续次相对路径会展开至<code>/</code>下，从而创建新的系统的<code>rootfs</code>，这也是从零搭建<code>linux</code>(<code>linux from scratch</code>)的重要操作之一。</h5><figure class="highlight dsconfig"><table><tbody><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><code class="hljs dsconfig">[<span class="hljs-string">root</span>@<span class="hljs-string">kong</span> <span class="hljs-string">rootfs</span>]<span class="hljs-comment"># tar cpf rootfs.tar .</span><br><span class="hljs-string">tar</span>: ./<span class="hljs-string">rootfs</span>.<span class="hljs-string">tar</span>: <span class="hljs-string">file</span> <span class="hljs-string">is</span> <span class="hljs-string">the</span> <span class="hljs-string">archive</span>; <span class="hljs-string">not</span> <span class="hljs-string">dumped</span><br>[<span class="hljs-string">root</span>@<span class="hljs-string">kong</span> <span class="hljs-string">rootfs</span>]<span class="hljs-comment">#</span><br>简单说明：<span class="hljs-string">busybox</span> –<span class="hljs-built_in">list-modules列出了busybox的所有模块，然后以此为基础，创建了一个小型的rootfs</span><br>[<span class="hljs-string">root</span>@<span class="hljs-string">kong</span> <span class="hljs-string">rootfs</span>]<span class="hljs-comment"># busybox –list-modules |wc -l</span><br><span class="hljs-string">389</span><br>[<span class="hljs-string">root</span>@<span class="hljs-string">kong</span> <span class="hljs-string">rootfs</span>]<span class="hljs-comment">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="准备Dockerfile"><a href="#准备Dockerfile" class="headerlink" title="准备Dockerfile"></a>准备<code>Dockerfile</code></h5><h5 id="准备一个一行的Dockerfile"><a href="#准备一个一行的Dockerfile" class="headerlink" title="准备一个一行的Dockerfile"></a>准备一个一行的<code>Dockerfile</code></h5><figure class="highlight autoit"><table><tbody><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><code class="hljs autoit">[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># vi Dockerfile</span><br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># cat Dockerfile</span><br>From scratch<br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="创建base镜像，由于没有发现具体的内容，所以未创建出具体镜像。另外，本文为了演示方便，直接在此处创建Dockerfile，这并不是一个好主意，实际的时候请不要这样做，如果当前目录下有100G的文件，就会无比缓慢，而且也不规范，无关物品需要清场。"><a href="#创建base镜像，由于没有发现具体的内容，所以未创建出具体镜像。另外，本文为了演示方便，直接在此处创建Dockerfile，这并不是一个好主意，实际的时候请不要这样做，如果当前目录下有100G的文件，就会无比缓慢，而且也不规范，无关物品需要清场。" class="headerlink" title="创建base镜像，由于没有发现具体的内容，所以未创建出具体镜像。另外，本文为了演示方便，直接在此处创建Dockerfile，这并不是一个好主意，实际的时候请不要这样做，如果当前目录下有100G的文件，就会无比缓慢，而且也不规范，无关物品需要清场。"></a>创建<code>base</code>镜像，由于没有发现具体的内容，所以未创建出具体镜像。另外，本文为了演示方便，直接在此处创建<code>Dockerfile</code>，这并不是一个好主意，实际的时候请不要这样做，如果当前目录下有100G的文件，就会无比缓慢，而且也不规范，无关物品需要清场。</h5><figure class="highlight autoit"><table><tbody><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><code class="hljs autoit">[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># docker build -t busyboxbase:latest .</span><br>Sending build context <span class="hljs-keyword">to</span> Docker daemon <span class="hljs-number">2.415</span> MB<br><span class="hljs-keyword">Step</span> <span class="hljs-number">1</span>/<span class="hljs-number">1</span> : FROM scratch<br>     —&gt;<br>No image was generated. Is your Dockerfile empty?<br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># docker images |grep busyboxbase</span><br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="from-scracth"><a href="#from-scracth" class="headerlink" title="from scracth"></a><code>from scracth</code></h5><h5 id="有From，这个scratch可以pull么，目前的版本已经将其作为一个保留名称"><a href="#有From，这个scratch可以pull么，目前的版本已经将其作为一个保留名称" class="headerlink" title="有From，这个scratch可以pull么，目前的版本已经将其作为一个保留名称"></a>有<code>From</code>，这个<code>scratch</code>可以<code>pull</code>么，目前的版本已经将其作为一个保留名称</h5><figure class="highlight coffeescript"><table><tbody><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><code class="hljs coffeescript">[root@kong rootfs]<span class="hljs-comment"># docker search scratch |grep ‘an explicitly empty’</span><br>docker.io docker.io/scratch an explicitly empty image, especially <span class="hljs-keyword">for</span> … <span class="hljs-number">407</span> [OK]<br>[root@kong rootfs]<span class="hljs-comment"># docker pull scratch</span><br>Using <span class="hljs-keyword">default</span> tag: latest<br><span class="hljs-built_in">Error</span> response <span class="hljs-keyword">from</span> daemon: ‘scratch’ <span class="hljs-keyword">is</span> a reserved name<br>[root@kong rootfs]<span class="hljs-comment">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="将此Dockerfile添加一行没有实际作用的，看看scratch到底是什么"><a href="#将此Dockerfile添加一行没有实际作用的，看看scratch到底是什么" class="headerlink" title="将此Dockerfile添加一行没有实际作用的，看看scratch到底是什么"></a>将此<code>Dockerfile</code>添加一行没有实际作用的，看看<code>scratch</code>到底是什么</h5><figure class="highlight autoit"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs autoit">[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># vi Dockerfile</span><br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># cat Dockerfile</span><br>From scratch<br>MAINTAINER LiuMiao &lt;liumiaocn<span class="hljs-symbol">@outlook</span>.com&gt;<br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="进行构建，发现产生了一个0字节的镜像文件，也与scratch的原意相通"><a href="#进行构建，发现产生了一个0字节的镜像文件，也与scratch的原意相通" class="headerlink" title="进行构建，发现产生了一个0字节的镜像文件，也与scratch的原意相通"></a>进行构建，发现产生了一个<code>0</code>字节的镜像文件，也与<code>scratch</code>的原意相通</h5><figure class="highlight autoit"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs autoit">[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># docker build -t busyboxbase:latest .</span><br>Sending build context <span class="hljs-keyword">to</span> Docker daemon <span class="hljs-number">2.415</span> MB<br><span class="hljs-keyword">Step</span> <span class="hljs-number">1</span>/<span class="hljs-number">2</span> : FROM scratch<br>     —&gt;<br><span class="hljs-keyword">Step</span> <span class="hljs-number">2</span>/<span class="hljs-number">2</span> : MAINTAINER LiuMiao &lt;liumiaocn<span class="hljs-symbol">@outlook</span>.com&gt;<br>     —&gt; Running <span class="hljs-keyword">in</span> b118fd7c73a7<br>     —&gt; <span class="hljs-number">2074</span>dc76c09e<br>Removing intermediate container b118fd7c73a7<br>Successfully built <span class="hljs-number">2074</span>dc76c09e<br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta"># docker images |grep busyboxbase</span><br>busyboxbase latest <span class="hljs-number">2074</span>dc76c09e <span class="hljs-number">14</span> seconds ago <span class="hljs-number">0</span> B<br>[root<span class="hljs-symbol">@kong</span> rootfs]<span class="hljs-meta">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="至此，我们理解了from-scratch确实不会有额外的添加，接下来我们像alpine那样添加如下两句"><a href="#至此，我们理解了from-scratch确实不会有额外的添加，接下来我们像alpine那样添加如下两句" class="headerlink" title="至此，我们理解了from scratch确实不会有额外的添加，接下来我们像alpine那样添加如下两句"></a>至此，我们理解了<code>from scratch</code>确实不会有额外的添加，接下来我们像<code>alpine</code>那样添加如下两句</h5><figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">ADD</span><span class="language-bash"> rootfs.tar /</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [“/bin/sh”]</span><br></code></pre></td></tr></tbody></table></figure><h5 id="我们的Dockerfile也是几乎一样的三行"><a href="#我们的Dockerfile也是几乎一样的三行" class="headerlink" title="我们的Dockerfile也是几乎一样的三行"></a>我们的<code>Dockerfile</code>也是几乎一样的三行</h5><figure class="highlight dockerfile"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs dockerfile">[root@kong rootfs]<span class="hljs-comment"># cat Dockerfile</span><br><span class="hljs-keyword">From</span> scratch<br><span class="hljs-keyword">ADD</span><span class="language-bash"> rootfs.tar /</span><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [“/bin/sh”]</span><br>[root@kong rootfs]<span class="hljs-comment">#</span><br></code></pre></td></tr></tbody></table></figure><h5 id="这样就创建了一个1M的busybox为基础的镜像"><a href="#这样就创建了一个1M的busybox为基础的镜像" class="headerlink" title="这样就创建了一个1M的busybox为基础的镜像"></a>这样就创建了一个<code>1M</code>的<code>busybox</code>为基础的镜像</h5><figure class="highlight llvm"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs llvm">[root<span class="hljs-title">@kong</span> rootfs]# docker build -t busyboxbase:latest .<br>Sending build context <span class="hljs-keyword">to</span> Docker daemon <span class="hljs-number">2.415</span> MB<br>Step <span class="hljs-number">1</span>/<span class="hljs-number">3</span> : FROM scratch<br>     —&gt;<br>Step <span class="hljs-number">2</span>/<span class="hljs-number">3</span> : ADD rootfs.tar /<br>     —&gt; <span class="hljs-number">0</span>fbb<span class="hljs-number">0</span><span class="hljs-keyword">c</span><span class="hljs-number">8</span><span class="hljs-keyword">c</span><span class="hljs-number">7579</span><br>Removing intermediate container <span class="hljs-number">8311e96</span>f<span class="hljs-number">456</span><span class="hljs-keyword">c</span><br>Step <span class="hljs-number">3</span>/<span class="hljs-number">3</span> : CMD /bin/sh<br>     —&gt; Running in efb<span class="hljs-number">85</span><span class="hljs-keyword">c</span><span class="hljs-number">4526</span>bf<br>     —&gt; <span class="hljs-number">02270</span><span class="hljs-keyword">c</span><span class="hljs-number">80</span>a<span class="hljs-number">4e4</span><br>Removing intermediate container efb<span class="hljs-number">85</span><span class="hljs-keyword">c</span><span class="hljs-number">4526</span>bf<br>Successfully built <span class="hljs-number">02270</span><span class="hljs-keyword">c</span><span class="hljs-number">80</span>a<span class="hljs-number">4e4</span><br>[root<span class="hljs-title">@kong</span> rootfs]# docker images |grep busyboxbase<br>busyboxbase latest <span class="hljs-number">02270</span><span class="hljs-keyword">c</span><span class="hljs-number">80</span>a<span class="hljs-number">4e4</span> <span class="hljs-number">9</span> seconds ago <span class="hljs-number">1.01</span> MB<br>[root<span class="hljs-title">@kong</span> rootfs]#<br></code></pre></td></tr></tbody></table></figure><h5 id="运行并使用"><a href="#运行并使用" class="headerlink" title="运行并使用"></a>运行并使用</h5><h5 id="使用docker-run发现此镜像所启动的容器并无异常之处"><a href="#使用docker-run发现此镜像所启动的容器并无异常之处" class="headerlink" title="使用docker run发现此镜像所启动的容器并无异常之处"></a>使用<code>docker run</code>发现此镜像所启动的容器并无异常之处</h5><figure class="highlight nix"><table><tbody><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><code class="hljs nix">[root@kong rootfs]<span class="hljs-comment"># docker run –rm -it busyboxbase sh</span><br><span class="hljs-symbol">/</span> <span class="hljs-comment"># hostname</span><br>b7f9e9646746<br><span class="hljs-symbol">/</span> <span class="hljs-comment"># uname -a</span><br>Linux b7f9e9646746 <span class="hljs-number">3.10</span>.<span class="hljs-number">0</span><span class="hljs-operator">-</span><span class="hljs-number">693</span>.el7.x86_64 <span class="hljs-comment">#1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 GNU/Linux</span><br><span class="hljs-symbol">/</span> <span class="hljs-comment">#</span><br></code></pre></td></tr></tbody></table></figure><h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><h5 id="这篇文章介绍了如何使用busybox结合from-scratch机制创建docker的基础镜像以及相关原理。本文利用busybox-1-28-1版本创建了一个1-01M的可用的基础镜像，从瑞士军刀到瑞士指甲刀，你可以继续优化到若干K都是可行的，但是到了10M以下其实应该更多考虑的是后续的扩展性和功能性的因素了。但是从另外的角度考虑，集成进来了那么多功能的同时，也将这些功能的不安定因素也集成进来了。利用from-scratch机制，创建小并且依赖性少的上下文环境是非常有用的。"><a href="#这篇文章介绍了如何使用busybox结合from-scratch机制创建docker的基础镜像以及相关原理。本文利用busybox-1-28-1版本创建了一个1-01M的可用的基础镜像，从瑞士军刀到瑞士指甲刀，你可以继续优化到若干K都是可行的，但是到了10M以下其实应该更多考虑的是后续的扩展性和功能性的因素了。但是从另外的角度考虑，集成进来了那么多功能的同时，也将这些功能的不安定因素也集成进来了。利用from-scratch机制，创建小并且依赖性少的上下文环境是非常有用的。" class="headerlink" title="这篇文章介绍了如何使用busybox结合from scratch机制创建docker的基础镜像以及相关原理。本文利用busybox 1.28.1版本创建了一个1.01M的可用的基础镜像，从瑞士军刀到瑞士指甲刀，你可以继续优化到若干K都是可行的，但是到了10M以下其实应该更多考虑的是后续的扩展性和功能性的因素了。但是从另外的角度考虑，集成进来了那么多功能的同时，也将这些功能的不安定因素也集成进来了。利用from scratch机制，创建小并且依赖性少的上下文环境是非常有用的。"></a>这篇文章介绍了如何使用<code>busybox</code>结合<code>from scratch</code>机制创建<code>docker</code>的基础镜像以及相关原理。本文利用<code>busybox 1.28.1</code>版本创建了一个1.01M的可用的基础镜像，从瑞士军刀到瑞士指甲刀，你可以继续优化到若干K都是可行的，但是到了10M以下其实应该更多考虑的是后续的扩展性和功能性的因素了。但是从另外的角度考虑，集成进来了那么多功能的同时，也将这些功能的不安定因素也集成进来了。利用<code>from scratch</code>机制，创建小并且依赖性少的上下文环境是非常有用的。</h5><h5 id="希望本文的内容对大家的学习或者工作具有一定的参考学习价值，谢谢大家对我们的支持"><a href="#希望本文的内容对大家的学习或者工作具有一定的参考学习价值，谢谢大家对我们的支持" class="headerlink" title="希望本文的内容对大家的学习或者工作具有一定的参考学习价值，谢谢大家对我们的支持"></a>希望本文的内容对大家的学习或者工作具有一定的参考学习价值，谢谢大家对我们的支持</h5>]]></content>
    
    
    <summary type="html">&lt;h5 id=&quot;今天小编就为大家分享一篇关于Docker利用busybox创建基础镜像-base-image-，小编觉得内容挺不错的，现在分享给大家，具有很好的参考价值，需要的朋友一起跟随小编来看看吧&quot;&gt;&lt;a href=&quot;#今天小编就为大家分享一篇关于Docker利用busybox创建基础镜像-base-image-，小编觉得内容挺不错的，现在分享给大家，具有很好的参考价值，需要的朋友一起跟随小编来看看吧&quot; class=&quot;headerlink&quot; title=&quot;今天小编就为大家分享一篇关于Docker利用busybox创建基础镜像(base image)，小编觉得内容挺不错的，现在分享给大家，具有很好的参考价值，需要的朋友一起跟随小编来看看吧&quot;&gt;&lt;/a&gt;今天小编就为大家分享一篇关于&lt;code&gt;Docker&lt;/code&gt;利用&lt;code&gt;busybox&lt;/code&gt;创建基础镜像(&lt;code&gt;base image&lt;/code&gt;)，小编觉得内容挺不错的，现在分享给大家，具有很好的参考价值，需要的朋友一起跟随小编来看看吧&lt;/h5&gt;&lt;h5 id=&quot;docker镜像的首行从FROM-alpine之类的镜像开始，但是最初的基础镜像是如何创建的，本文使用一个busybox创建一个基础镜像，相信在此过程中会对docker一些相关的概念有进一步的理解。&quot;&gt;&lt;a href=&quot;#docker镜像的首行从FROM-alpine之类的镜像开始，但是最初的基础镜像是如何创建的，本文使用一个busybox创建一个基础镜像，相信在此过程中会对docker一些相关的概念有进一步的理解。&quot; class=&quot;headerlink&quot; title=&quot;docker镜像的首行从FROM alpine之类的镜像开始，但是最初的基础镜像是如何创建的，本文使用一个busybox创建一个基础镜像，相信在此过程中会对docker一些相关的概念有进一步的理解。&quot;&gt;&lt;/a&gt;&lt;code&gt;docker&lt;/code&gt;镜像的首行从&lt;code&gt;FROM alpine&lt;/code&gt;之类的镜像开始，但是最初的基础镜像是如何创建的，本文使用一个&lt;code&gt;busybox&lt;/code&gt;创建一个基础镜像，相信在此过程中会对&lt;code&gt;docker&lt;/code&gt;一些相关的概念有进一步的理解。&lt;/h5&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Hexo-Blog Docker搭建本地环境与持续集成</title>
    <link href="https://www.qxz5637.top/2024/05/10/Hexo-Blog-Docker%E6%90%AD%E5%BB%BA%E6%9C%AC%E5%9C%B0%E7%8E%AF%E5%A2%83%E4%B8%8E%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/"/>
    <id>https://www.qxz5637.top/2024/05/10/Hexo-Blog-Docker%E6%90%AD%E5%BB%BA%E6%9C%AC%E5%9C%B0%E7%8E%AF%E5%A2%83%E4%B8%8E%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/</id>
    <published>2024-05-10T04:12:22.000Z</published>
    <updated>2024-05-10T12:16:21.801Z</updated>
    
    <content type="html"><![CDATA[<h5 id="Hexo-Blog-indigo-hexo6"><a href="#Hexo-Blog-indigo-hexo6" class="headerlink" title="Hexo-Blog (indigo-hexo6)"></a>Hexo-Blog (indigo-hexo6)</h5><h5 id="该博客使用了-GitHub-Pages-Hexo-indigo-hexo6-主题搭建"><a href="#该博客使用了-GitHub-Pages-Hexo-indigo-hexo6-主题搭建" class="headerlink" title="该博客使用了 GitHub Pages + Hexo + indigo-hexo6 主题搭建"></a>该博客使用了 <code>GitHub Pages + Hexo + indigo-hexo6</code> 主题搭建</h5><h5 id="GitHub-Pages-允许我们-创建以自己用户名开头的username-github-io仓库用来搭建自己的静态页面网站或者博客，而-Hexo-本身就是一款支持-Markdown-静态化博客框架，有多种主题可供选择，并且上手简单。"><a href="#GitHub-Pages-允许我们-创建以自己用户名开头的username-github-io仓库用来搭建自己的静态页面网站或者博客，而-Hexo-本身就是一款支持-Markdown-静态化博客框架，有多种主题可供选择，并且上手简单。" class="headerlink" title="GitHub Pages 允许我们 创建以自己用户名开头的username.github.io仓库用来搭建自己的静态页面网站或者博客，而 Hexo 本身就是一款支持 Markdown 静态化博客框架，有多种主题可供选择，并且上手简单。"></a><code>GitHub Pages</code> 允许我们 创建以自己用户名开头的<code>username.github.io</code>仓库用来搭建自己的静态页面网站或者博客，而 <code>Hexo</code> 本身就是一款支持 <code>Markdown</code> 静态化博客框架，有多种主题可供选择，并且上手简单。</h5><span id="more"></span><h5 id="另外为了解决平时在写好文章想先本地预览，但是又不在自己电脑旁边或者使用公司电脑的时候要重新安装部署一遍-nodejs-和-hexo-这些东西，所以增加了docker来解决环境的问题。"><a href="#另外为了解决平时在写好文章想先本地预览，但是又不在自己电脑旁边或者使用公司电脑的时候要重新安装部署一遍-nodejs-和-hexo-这些东西，所以增加了docker来解决环境的问题。" class="headerlink" title="另外为了解决平时在写好文章想先本地预览，但是又不在自己电脑旁边或者使用公司电脑的时候要重新安装部署一遍 nodejs 和 hexo 这些东西，所以增加了docker来解决环境的问题。"></a>另外为了解决平时在写好文章想先本地预览，但是又不在自己电脑旁边或者使用公司电脑的时候要重新安装部署一遍 <code>nodejs</code> 和 <code>hexo</code> 这些东西，所以增加了<code>docker</code>来解决环境的问题。</h5><h5 id="使用-Dockerfile-docker-compose-文件，Dockerfile"><a href="#使用-Dockerfile-docker-compose-文件，Dockerfile" class="headerlink" title="使用 Dockerfile + docker-compose 文件，Dockerfile"></a>使用 <code>Dockerfile + docker-compose</code> 文件，<code>Dockerfile</code></h5><figure class="highlight dockerfile"><table><tbody><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><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> node:<span class="hljs-number">14</span> AS builder<br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /app</span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> . .</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> npm install --no-fund &amp;&amp; npx hexo clean &amp;&amp; npx hexo generate</span><br><span class="hljs-keyword">FROM</span> nginx:alpine<br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> /usr/share/nginx/html</span><br><span class="hljs-keyword">COPY</span><span class="language-bash"> --from=builder /app/public /usr/share/nginx/html</span><br><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">8080</span><br></code></pre></td></tr></tbody></table></figure><h5 id="提醒：在中国大陆由于某些众所周知的网络原因-npm-install-命令有时候会失败-可以多试几次-也可以使用国内镜像或者科学上网安装。"><a href="#提醒：在中国大陆由于某些众所周知的网络原因-npm-install-命令有时候会失败-可以多试几次-也可以使用国内镜像或者科学上网安装。" class="headerlink" title="提醒：在中国大陆由于某些众所周知的网络原因, npm install 命令有时候会失败, 可以多试几次, 也可以使用国内镜像或者科学上网安装。"></a>提醒：在中国大陆由于某些众所周知的网络原因, <code>npm install</code> 命令有时候会失败, 可以多试几次, 也可以使用国内镜像或者科学上网安装。</h5><figure class="highlight dts"><table><tbody><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></pre></td><td class="code"><pre><code class="hljs dts">docker-compose<br><span class="hljs-symbol">version:</span> <span class="hljs-string">'3'</span><br><span class="hljs-symbol">services:</span><br><span class="hljs-symbol">  hexo:</span><br><span class="hljs-symbol">    build:</span><br><span class="hljs-symbol">      context:</span> .<br><span class="hljs-symbol">      dockerfile:</span> Dockerfile<br><span class="hljs-symbol">    image:</span> chuchuzz426/blog-hexo:<span class="hljs-number">1.0</span><br><span class="hljs-symbol">    ports:</span><br>      - <span class="hljs-string">"8080:80"</span><br></code></pre></td></tr></tbody></table></figure><h5 id="如此-git-clone-下来的时候-能立马部署出一套本地环境，使用简单-开袋即食😋"><a href="#如此-git-clone-下来的时候-能立马部署出一套本地环境，使用简单-开袋即食😋" class="headerlink" title="如此 git clone 下来的时候 能立马部署出一套本地环境，使用简单, 开袋即食😋"></a>如此 <code>git clone</code> 下来的时候 能立马部署出一套本地环境，使用简单, 开袋即食😋</h5><figure class="highlight crmsh"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs crmsh"><span class="hljs-comment"># 拉取src分支源码</span><br>git <span class="hljs-keyword">clone</span> <span class="hljs-title">-b</span> src git@github.com:chuchu-z/chuchu-z.github.io.git<br></code></pre></td></tr></tbody></table></figure><figure class="highlight mipsasm"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs mipsasm"><span class="hljs-comment"># 在项目目录执行</span><br>docker-compose <span class="hljs-keyword">build </span>--no-<span class="hljs-keyword">cache </span>&amp;&amp; docker-compose up<br></code></pre></td></tr></tbody></table></figure><h5 id="然后就可以打开-http-127-0-0-1-8080-预览啦✨"><a href="#然后就可以打开-http-127-0-0-1-8080-预览啦✨" class="headerlink" title="然后就可以打开 http://127.0.0.1:8080/ 预览啦✨"></a>然后就可以打开 <code>http://127.0.0.1:8080/</code> 预览啦✨</h5><h5 id="持续集成自动部署"><a href="#持续集成自动部署" class="headerlink" title="持续集成自动部署"></a>持续集成自动部署</h5><h5 id="为了发布文章push-到-src-分支后能自动更新到博客-使用了-GitHub-Actions-来实现自动部署"><a href="#为了发布文章push-到-src-分支后能自动更新到博客-使用了-GitHub-Actions-来实现自动部署" class="headerlink" title="为了发布文章push 到 src 分支后能自动更新到博客, 使用了 GitHub Actions 来实现自动部署"></a>为了发布文章<code>push</code> 到 <code>src</code> 分支后能自动更新到博客, 使用了 <code>GitHub Actions</code> 来实现自动部署</h5><h5 id="通过使用-GitHub-Actions，我们可以实现自动化的软件开发流程，提高开发效率和代码质量，它还可以帮助团队协同工作，确保代码的集成和部署过程更加可靠和一致"><a href="#通过使用-GitHub-Actions，我们可以实现自动化的软件开发流程，提高开发效率和代码质量，它还可以帮助团队协同工作，确保代码的集成和部署过程更加可靠和一致" class="headerlink" title="通过使用 GitHub Actions，我们可以实现自动化的软件开发流程，提高开发效率和代码质量，它还可以帮助团队协同工作，确保代码的集成和部署过程更加可靠和一致"></a>通过使用 <code>GitHub Actions</code>，我们可以实现自动化的软件开发流程，提高开发效率和代码质量，它还可以帮助团队协同工作，确保代码的集成和部署过程更加可靠和一致</h5><figure class="highlight nix"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><code class="hljs nix"><span class="hljs-comment"># Action 的名字</span><br><span class="hljs-params">name:</span> Hexo Auto Deploy<br><br><span class="hljs-params">on:</span><br>  <span class="hljs-comment"># 触发条件1：src 分支收到 push 后执行任务。</span><br>  <span class="hljs-params">push:</span><br>    <span class="hljs-params">branches:</span><br>      <span class="hljs-operator">-</span> src<br>  <span class="hljs-comment"># 触发条件2：手动按钮</span><br>  <span class="hljs-params">workflow_dispatch:</span><br><br><span class="hljs-comment"># 这里放环境变量,需要替换成你自己的</span><br><span class="hljs-params">env:</span><br>  <span class="hljs-comment"># Hexo 编译后使用此 git 用户部署到 github 仓库</span><br>  <span class="hljs-params">GIT_USER:</span> chuchu-z<br>  <span class="hljs-comment"># Hexo 编译后使用此 git 邮箱部署到 github 仓库</span><br>  <span class="hljs-params">GIT_EMAIL:</span> chuchuzz426@gmail.com<br>  <span class="hljs-comment"># Hexo 编译后要部署的 github 仓库</span><br>  <span class="hljs-params">GIT_DEPLOY_REPO:</span> chuchu-z<span class="hljs-symbol">/chuchu-z.github.io</span><br>  <span class="hljs-comment"># Hexo 编译后要部署到的分支</span><br>  <span class="hljs-params">GIT_DEPLOY_BRANCH:</span> master<br><br><span class="hljs-params">jobs:</span><br>  <span class="hljs-params">build:</span><br>    <span class="hljs-params">name:</span> Build on node ${{ matrix.node_version }} and ${{ matrix.os }}<br>    <span class="hljs-params">runs-on:</span> ubuntu-latest<br>    <span class="hljs-params">if:</span> github.event.repository.owner.id <span class="hljs-operator">==</span> github.event.sender.id<br>    <span class="hljs-params">strategy:</span><br>      <span class="hljs-params">matrix:</span><br>        <span class="hljs-params">os:</span> [ubuntu-latest]<br>        <span class="hljs-params">node_version:</span> [<span class="hljs-number">14</span>]<br><br>    <span class="hljs-params">steps:</span><br>      <span class="hljs-operator">-</span> <span class="hljs-params">name:</span> Checkout<br>        <span class="hljs-params">uses:</span> actions<span class="hljs-operator">/</span>checkout@v2<br><br>      <span class="hljs-operator">-</span> <span class="hljs-params">name:</span> Checkout deploy repo<br>        <span class="hljs-params">uses:</span> actions<span class="hljs-operator">/</span>checkout@v2<br>        <span class="hljs-params">with:</span><br>          <span class="hljs-params">repository:</span> ${{ env.GIT_DEPLOY_REPO }}<br>          <span class="hljs-params">ref:</span> ${{ env.GIT_DEPLOY_BRANCH }}<br>          <span class="hljs-params">path:</span> .deploy_git<br><br>      <span class="hljs-operator">-</span> <span class="hljs-params">name:</span> Use Node.js ${{ matrix.node_version }}<br>        <span class="hljs-params">uses:</span> actions<span class="hljs-operator">/</span>setup-node@v1<br>        <span class="hljs-params">with:</span><br>          <span class="hljs-params">node-version:</span> ${{ matrix.node_version }}<br><br>      <span class="hljs-operator">-</span> <span class="hljs-params">name:</span> Configuration environment<br>        <span class="hljs-params">env:</span><br>          <span class="hljs-params">HEXO_DEPLOY_PRI:</span> ${{secrets.HEXO_DEPLOY_PRI}}<br>        <span class="hljs-params">run:</span> |<br>          sudo timedatectl set-timezone <span class="hljs-string">"Asia/Shanghai"</span><br>          mkdir <span class="hljs-operator">-</span>p ~<span class="hljs-operator">/</span>.ssh<span class="hljs-symbol">/</span><br>          echo <span class="hljs-string">"$HEXO_DEPLOY_PRI"</span> <span class="hljs-operator">&gt;</span> <span class="hljs-symbol">~/.ssh/id_rsa</span><br>          chmod <span class="hljs-number">600</span> <span class="hljs-symbol">~/.ssh/id_rsa</span><br>          ssh-keyscan <span class="hljs-operator">-</span>t rsa github.com <span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span> <span class="hljs-symbol">~/.ssh/known_hosts</span><br>          <span class="hljs-comment"># coding 已取消同步</span><br>          ssh-keyscan <span class="hljs-operator">-</span>t rsa e.coding.net <span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span> <span class="hljs-symbol">~/.ssh/known_hosts</span><br>          ssh-keyscan <span class="hljs-operator">-</span>t rsa gitee.com <span class="hljs-operator">&gt;</span><span class="hljs-operator">&gt;</span> <span class="hljs-symbol">~/.ssh/known_hosts</span><br>          git config <span class="hljs-operator">-</span>-global user.name $GIT_USER<br>          git config <span class="hljs-operator">-</span>-global user.email $GIT_EMAIL<br><br>      <span class="hljs-operator">-</span> <span class="hljs-params">name:</span> Install dependencies<br>        <span class="hljs-params">run:</span> npm install <span class="hljs-operator">-</span>-no-fund<br><br>      <span class="hljs-operator">-</span> <span class="hljs-params">name:</span> Deploy hexo<br>        <span class="hljs-params">run:</span> |<br>          npm run deploy<br></code></pre></td></tr></tbody></table></figure><h5 id="触发条件为每当有push-代码的时候将自动按照-github-workflows-deploy-yml下的配置文件构造部署环境，相当于帮我们执行了-hexo-generate-和-hexo-deploy-然后hexo-deploy会根据项目根目录下的-config-yml配置文件。把编译好的静态文件更新到以自己用户名开头的username-github-io仓库的-master-分支上，这样就完成了自动化部署啦。"><a href="#触发条件为每当有push-代码的时候将自动按照-github-workflows-deploy-yml下的配置文件构造部署环境，相当于帮我们执行了-hexo-generate-和-hexo-deploy-然后hexo-deploy会根据项目根目录下的-config-yml配置文件。把编译好的静态文件更新到以自己用户名开头的username-github-io仓库的-master-分支上，这样就完成了自动化部署啦。" class="headerlink" title="触发条件为每当有push 代码的时候将自动按照.github/workflows/deploy.yml下的配置文件构造部署环境，相当于帮我们执行了 hexo generate 和 hexo deploy 然后hexo deploy会根据项目根目录下的_config.yml配置文件。把编译好的静态文件更新到以自己用户名开头的username.github.io仓库的 master 分支上，这样就完成了自动化部署啦。"></a>触发条件为每当有<code>push</code> 代码的时候将自动按照.<code>github/workflows/deploy.yml</code>下的配置文件构造部署环境，相当于帮我们执行了 <code>hexo generate</code> 和<code> hexo deploy</code> 然后<code>hexo deploy</code>会根据项目根目录下的<code>_config.yml</code>配置文件。把编译好的静态文件更新到以自己用户名开头的<code>username.github.io</code>仓库的 <code>master</code> 分支上，这样就完成了自动化部署啦。</h5><figure class="highlight nix"><table><tbody><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><code class="hljs nix"><span class="hljs-params">deploy:</span><br>  <span class="hljs-params">type:</span> git<br>  <span class="hljs-comment"># repo: git@github.com:chuchu-z/chuchu-z.github.io.git #构建机器上没有配置 ssh 免密,所以使用https</span><br>  <span class="hljs-params">repo:</span> https:<span class="hljs-operator">//</span>github_token@github.com<span class="hljs-symbol">/chuchu-z/chuchu-z.github.io.git</span><br>  <span class="hljs-params">branch:</span> master<br>  <span class="hljs-params">message:</span> GitHub Actions 自动部署:{{ now('YYYY-MM-DD HH:mm:ss') }}<br></code></pre></td></tr></tbody></table></figure><p>👉 博客地址: <a href="http://chuchu-z.com/">http://chuchu-z.com</a></p><p>👉 GitHub地址: <a href="https://github.com/chuchu-z/chuchu-z.github.io">https://github.com/chuchu-z/chuchu-z.github.io</a></p>]]></content>
    
    
    <summary type="html">&lt;h5 id=&quot;Hexo-Blog-indigo-hexo6&quot;&gt;&lt;a href=&quot;#Hexo-Blog-indigo-hexo6&quot; class=&quot;headerlink&quot; title=&quot;Hexo-Blog (indigo-hexo6)&quot;&gt;&lt;/a&gt;Hexo-Blog (indigo-hexo6)&lt;/h5&gt;&lt;h5 id=&quot;该博客使用了-GitHub-Pages-Hexo-indigo-hexo6-主题搭建&quot;&gt;&lt;a href=&quot;#该博客使用了-GitHub-Pages-Hexo-indigo-hexo6-主题搭建&quot; class=&quot;headerlink&quot; title=&quot;该博客使用了 GitHub Pages + Hexo + indigo-hexo6 主题搭建&quot;&gt;&lt;/a&gt;该博客使用了 &lt;code&gt;GitHub Pages + Hexo + indigo-hexo6&lt;/code&gt; 主题搭建&lt;/h5&gt;&lt;h5 id=&quot;GitHub-Pages-允许我们-创建以自己用户名开头的username-github-io仓库用来搭建自己的静态页面网站或者博客，而-Hexo-本身就是一款支持-Markdown-静态化博客框架，有多种主题可供选择，并且上手简单。&quot;&gt;&lt;a href=&quot;#GitHub-Pages-允许我们-创建以自己用户名开头的username-github-io仓库用来搭建自己的静态页面网站或者博客，而-Hexo-本身就是一款支持-Markdown-静态化博客框架，有多种主题可供选择，并且上手简单。&quot; class=&quot;headerlink&quot; title=&quot;GitHub Pages 允许我们 创建以自己用户名开头的username.github.io仓库用来搭建自己的静态页面网站或者博客，而 Hexo 本身就是一款支持 Markdown 静态化博客框架，有多种主题可供选择，并且上手简单。&quot;&gt;&lt;/a&gt;&lt;code&gt;GitHub Pages&lt;/code&gt; 允许我们 创建以自己用户名开头的&lt;code&gt;username.github.io&lt;/code&gt;仓库用来搭建自己的静态页面网站或者博客，而 &lt;code&gt;Hexo&lt;/code&gt; 本身就是一款支持 &lt;code&gt;Markdown&lt;/code&gt; 静态化博客框架，有多种主题可供选择，并且上手简单。&lt;/h5&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>Dockerfile学习And构建Hexo镜像</title>
    <link href="https://www.qxz5637.top/2024/05/09/Dockerfile%E5%AD%A6%E4%B9%A0And%E6%9E%84%E5%BB%BAHexo%E9%95%9C%E5%83%8F/"/>
    <id>https://www.qxz5637.top/2024/05/09/Dockerfile%E5%AD%A6%E4%B9%A0And%E6%9E%84%E5%BB%BAHexo%E9%95%9C%E5%83%8F/</id>
    <published>2024-05-09T15:08:36.000Z</published>
    <updated>2024-05-10T12:10:40.075Z</updated>
    
    <content type="html"><![CDATA[<h5 id="制作一个镜像可以使用docker-commit和定制Dockerfile，但推荐的是写Dockerfile。"><a href="#制作一个镜像可以使用docker-commit和定制Dockerfile，但推荐的是写Dockerfile。" class="headerlink" title="制作一个镜像可以使用docker commit和定制Dockerfile，但推荐的是写Dockerfile。"></a>制作一个镜像可以使用<code>docker commit</code>和定制<code>Dockerfile</code>，但推荐的是写<code>Dockerfile</code>。</h5><h5 id="因为docker-commit是一个暗箱操作，除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知，而且会加入一些没用的操作导致镜像臃肿。"><a href="#因为docker-commit是一个暗箱操作，除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知，而且会加入一些没用的操作导致镜像臃肿。" class="headerlink" title="因为docker commit是一个暗箱操作，除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知，而且会加入一些没用的操作导致镜像臃肿。"></a>因为<code>docker commit</code>是一个暗箱操作，除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知，而且会加入一些没用的操作导致镜像臃肿。</h5><span id="more"></span><h4 id="Build-Images"><a href="#Build-Images" class="headerlink" title="Build Images"></a><code>Build Images</code></h4><h5 id="首先在当前空目录创建一个Dockerfile："><a href="#首先在当前空目录创建一个Dockerfile：" class="headerlink" title="首先在当前空目录创建一个Dockerfile："></a>首先在当前空目录创建一个<code>Dockerfile</code>：</h5><figure class="highlight dockerfile"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">FROM</span> ubuntu:latest<br><br><span class="hljs-keyword">ENV</span> BLOG_PATH /root/blog<br><span class="hljs-keyword">ENV</span> NODE_VERSION <span class="hljs-number">6</span><br><br><span class="hljs-keyword">MAINTAINER</span> yangbingdong &lt;yangbingdong1994@gmail.com&gt;<br><br><span class="hljs-keyword">RUN</span><span class="language-bash"> \</span><br><span class="language-bash">    apt-get update -y &amp;&amp; \</span><br><span class="language-bash">    apt-get install -y git curl libpng-dev &amp;&amp; \</span><br><span class="language-bash">    curl -sL https://deb.nodesource.com/setup_<span class="hljs-variable">$NODE_VERSION</span>.x | bash - &amp;&amp; \</span><br><span class="language-bash">    apt-get install -y nodejs &amp;&amp; \</span><br><span class="language-bash">    apt-get clean &amp;&amp; \</span><br><span class="language-bash">    apt-get autoclean &amp;&amp; \</span><br><span class="language-bash">    <span class="hljs-built_in">rm</span> -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* &amp;&amp; \</span><br><span class="language-bash">    npm install -g hexo-cli</span><br><br><span class="hljs-keyword">WORKDIR</span><span class="language-bash"> <span class="hljs-variable">$BLOG_PATH</span></span><br><br><span class="hljs-keyword">VOLUME</span><span class="language-bash"> [<span class="hljs-string">"<span class="hljs-variable">$BLOG_PATH</span>"</span>, <span class="hljs-string">"/root/.ssh"</span>]</span><br><br><span class="hljs-keyword">EXPOSE</span> <span class="hljs-number">4000</span><br><br><span class="hljs-keyword">CMD</span><span class="language-bash"> [<span class="hljs-string">'/bin/bash'</span>]</span><br></code></pre></td></tr></tbody></table></figure><h5 id="然后在当前目录打开终端："><a href="#然后在当前目录打开终端：" class="headerlink" title="然后在当前目录打开终端："></a>然后在当前目录打开终端：</h5><figure class="highlight xml"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml">docker build -t <span class="hljs-tag">&lt;<span class="hljs-name">repo-name</span>&gt;</span>/<span class="hljs-tag">&lt;<span class="hljs-name">image-name</span>&gt;</span>:<span class="hljs-tag">&lt;<span class="hljs-name">tag</span>&gt;</span> .<br></code></pre></td></tr></tbody></table></figure><h5 id="其中表示仓库名，与远程仓库（如docker-hub）名字要一致，表示标签，不给默认latest，都是可选项，例如可以写成这样："><a href="#其中表示仓库名，与远程仓库（如docker-hub）名字要一致，表示标签，不给默认latest，都是可选项，例如可以写成这样：" class="headerlink" title="其中<repo-name>表示仓库名，与远程仓库（如docker hub）名字要一致，<tag>表示标签，不给默认latest，都是可选项，例如可以写成这样："></a>其中<code>&lt;repo-name&gt;</code>表示仓库名，与远程仓库（如<code>docker hub</code>）名字要一致，<code>&lt;tag&gt;</code>表示标签，不给默认<code>latest</code>，都是可选项，例如可以写成这样：</h5><figure class="highlight excel"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs excel">docker build -<span class="hljs-built_in">t</span> &lt;<span class="hljs-built_in">image</span>-name&gt; .<br></code></pre></td></tr></tbody></table></figure><h5 id="看到-Successfully-built就表示构建成功了"><a href="#看到-Successfully-built就表示构建成功了" class="headerlink" title="看到 Successfully built就表示构建成功了"></a>看到 <code>Successfully built</code>就表示构建成功了</h5><h5 id="注意docker-build-命令最后有一个-表示构建的上下文，镜像构建需要把上下文的东西上传到Docker引擎去构建。"><a href="#注意docker-build-命令最后有一个-表示构建的上下文，镜像构建需要把上下文的东西上传到Docker引擎去构建。" class="headerlink" title="注意docker build 命令最后有一个 .表示构建的上下文，镜像构建需要把上下文的东西上传到Docker引擎去构建。"></a>注意<code>docker build</code> 命令最后有一个 .表示构建的上下文，镜像构建需要把上下文的东西上传到<code>Docker</code>引擎去构建。</h5><h4 id="Dockerfile-指令"><a href="#Dockerfile-指令" class="headerlink" title="Dockerfile 指令"></a><code>Dockerfile</code> 指令</h4><h5 id="From-指定基础镜像"><a href="#From-指定基础镜像" class="headerlink" title="From 指定基础镜像"></a><code>From</code> 指定基础镜像</h5><h5 id="所谓定制镜像，那一定是以一个镜像为基础，在其上进行定制。而-FROM-就是指定基础镜像，因此一个-Dockerfile-中-FROM-是必备的指令，并且必须是第一条指令。"><a href="#所谓定制镜像，那一定是以一个镜像为基础，在其上进行定制。而-FROM-就是指定基础镜像，因此一个-Dockerfile-中-FROM-是必备的指令，并且必须是第一条指令。" class="headerlink" title="所谓定制镜像，那一定是以一个镜像为基础，在其上进行定制。而 FROM 就是指定基础镜像，因此一个 Dockerfile 中 FROM 是必备的指令，并且必须是第一条指令。"></a>所谓定制镜像，那一定是以一个镜像为基础，在其上进行定制。而 FROM 就是指定基础镜像，因此一个 <code>Dockerfile</code> 中 <code>FROM</code> 是必备的指令，并且必须是第一条指令。</h5><h5 id="在-Docker-Hub上有非常多的高质量的官方镜像，-有可以直接拿来使用的服务类的镜像，如-nginx、redis、mongo、mysql、httpd、php、tomcat-等；-也有一些方便开发、构建、运行各种语言应用的镜像，如-node、openjdk、python、ruby、golang-等。-可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。-如果没有找到对应服务的镜像，官方镜像中还提供了一些更为基础的操作系统镜像，如-ubuntu、debian、centos、fedora、alpine-等，这些操作系统的软件库为我们提供了更广阔的扩展空间。"><a href="#在-Docker-Hub上有非常多的高质量的官方镜像，-有可以直接拿来使用的服务类的镜像，如-nginx、redis、mongo、mysql、httpd、php、tomcat-等；-也有一些方便开发、构建、运行各种语言应用的镜像，如-node、openjdk、python、ruby、golang-等。-可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。-如果没有找到对应服务的镜像，官方镜像中还提供了一些更为基础的操作系统镜像，如-ubuntu、debian、centos、fedora、alpine-等，这些操作系统的软件库为我们提供了更广阔的扩展空间。" class="headerlink" title="在 Docker Hub上有非常多的高质量的官方镜像， 有可以直接拿来使用的服务类的镜像，如 nginx、redis、mongo、mysql、httpd、php、tomcat 等； 也有一些方便开发、构建、运行各种语言应用的镜像，如 node、openjdk、python、ruby、golang 等。 可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。 如果没有找到对应服务的镜像，官方镜像中还提供了一些更为基础的操作系统镜像，如 ubuntu、debian、centos、fedora、alpine 等，这些操作系统的软件库为我们提供了更广阔的扩展空间。"></a>在 <code>Docker Hub</code>上有非常多的高质量的官方镜像， 有可以直接拿来使用的服务类的镜像，如 <code>nginx</code>、<code>redis</code>、<code>mongo</code>、<code>mysql</code>、<code>httpd</code>、<code>php</code>、<code>tomcat</code> 等； 也有一些方便开发、构建、运行各种语言应用的镜像，如 <code>node</code>、<code>openjdk</code>、<code>python</code>、<code>ruby</code>、<code>golang</code> 等。 可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。 如果没有找到对应服务的镜像，官方镜像中还提供了一些更为基础的操作系统镜像，如 <code>ubuntu</code>、<code>debian</code>、<code>centos</code>、<code>fedora</code>、<code>alpine</code> 等，这些操作系统的软件库为我们提供了更广阔的扩展空间。</h5><h5 id="除了选择现有镜像为基础镜像外，Docker-还存在一个特殊的镜像，名为-scratch。这个镜像是虚拟的概念，并不实际存在，它表示一个空白的镜像。"><a href="#除了选择现有镜像为基础镜像外，Docker-还存在一个特殊的镜像，名为-scratch。这个镜像是虚拟的概念，并不实际存在，它表示一个空白的镜像。" class="headerlink" title="除了选择现有镜像为基础镜像外，Docker 还存在一个特殊的镜像，名为 scratch。这个镜像是虚拟的概念，并不实际存在，它表示一个空白的镜像。"></a>除了选择现有镜像为基础镜像外，<code>Docker</code> 还存在一个特殊的镜像，名为 <code>scratch</code>。这个镜像是虚拟的概念，并不实际存在，它表示一个空白的镜像。</h5><h5 id="RUN-执行命令"><a href="#RUN-执行命令" class="headerlink" title="RUN 执行命令"></a><code>RUN</code> 执行命令</h5><h5 id="RUN-指令是用来执行命令行命令的。由于命令行的强大能力，RUN-指令在定制镜像时是最常用的指令之一。其格式有两种："><a href="#RUN-指令是用来执行命令行命令的。由于命令行的强大能力，RUN-指令在定制镜像时是最常用的指令之一。其格式有两种：" class="headerlink" title="RUN 指令是用来执行命令行命令的。由于命令行的强大能力，RUN 指令在定制镜像时是最常用的指令之一。其格式有两种："></a><code>RUN</code> 指令是用来执行命令行命令的。由于命令行的强大能力，RUN 指令在定制镜像时是最常用的指令之一。其格式有两种：</h5><h5 id="shell-格式：RUN-，就像直接在命令行中输入的命令一样。刚才写的-Dockrfile-中的-RUN-指令就是这种格式。"><a href="#shell-格式：RUN-，就像直接在命令行中输入的命令一样。刚才写的-Dockrfile-中的-RUN-指令就是这种格式。" class="headerlink" title="shell 格式：RUN <命令>，就像直接在命令行中输入的命令一样。刚才写的 Dockrfile 中的 RUN 指令就是这种格式。"></a><code>shell</code> 格式：<code>RUN</code> &lt;命令&gt;，就像直接在命令行中输入的命令一样。刚才写的 <code>Dockrfile</code> 中的 RUN 指令就是这种格式。</h5><figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">'&lt;h1&gt;Hello, Docker!&lt;/h1&gt;'</span> &gt; /usr/share/nginx/html/index.html</span><br></code></pre></td></tr></tbody></table></figure><h5 id="exec-格式：RUN-“可执行文件”-“参数1”-“参数2”-，这更像是函数调用中的格式。"><a href="#exec-格式：RUN-“可执行文件”-“参数1”-“参数2”-，这更像是函数调用中的格式。" class="headerlink" title="exec 格式：RUN [“可执行文件”, “参数1”, “参数2”]，这更像是函数调用中的格式。"></a><code>exec</code> 格式：<code>RUN</code> [“可执行文件”, “参数1”, “参数2”]，这更像是函数调用中的格式。</h5><h5 id="注意："><a href="#注意：" class="headerlink" title="注意："></a>注意：</h5><h5 id="RUN命令尽量精简，也就是像上面一样一个RUN（使用-），如果分开写很多个RUN会导致镜像铺了很多层从而臃肿。"><a href="#RUN命令尽量精简，也就是像上面一样一个RUN（使用-），如果分开写很多个RUN会导致镜像铺了很多层从而臃肿。" class="headerlink" title="RUN命令尽量精简，也就是像上面一样一个RUN（使用$$ \），如果分开写很多个RUN会导致镜像铺了很多层从而臃肿。"></a>RUN命令尽量精简，也就是像上面一样一个RUN（使用$$ \），如果分开写很多个RUN会导致镜像铺了很多层从而臃肿。</h5><h5 id="RUN最后记住清理掉没用的垃圾，很多人初学-Docker-制作出了很臃肿的镜像的原因之一，就是忘记了每一层构建的最后一定要清理掉无关文件。"><a href="#RUN最后记住清理掉没用的垃圾，很多人初学-Docker-制作出了很臃肿的镜像的原因之一，就是忘记了每一层构建的最后一定要清理掉无关文件。" class="headerlink" title="RUN最后记住清理掉没用的垃圾，很多人初学 Docker 制作出了很臃肿的镜像的原因之一，就是忘记了每一层构建的最后一定要清理掉无关文件。"></a>RUN最后记住清理掉没用的垃圾，很多人初学 Docker 制作出了很臃肿的镜像的原因之一，就是忘记了每一层构建的最后一定要清理掉无关文件。</h5><h5 id="COPY-复制文件"><a href="#COPY-复制文件" class="headerlink" title="COPY 复制文件"></a><code>COPY</code> 复制文件</h5><h5 id="格式："><a href="#格式：" class="headerlink" title="格式："></a>格式：</h5><h5 id="COPY-…"><a href="#COPY-…" class="headerlink" title="COPY <源路径>… <目标路径>"></a><code>COPY</code> &lt;源路径&gt;… &lt;目标路径&gt;</h5><h5 id="COPY-“”-…-“”"><a href="#COPY-“”-…-“”" class="headerlink" title="COPY [“<源路径1>”,… “<目标路径>”]"></a><code>COPY</code> [“&lt;源路径1&gt;”,… “&lt;目标路径&gt;”]</h5><h5 id="和-RUN-指令一样，也有两种格式，一种类似于命令行，一种类似于函数调用。"><a href="#和-RUN-指令一样，也有两种格式，一种类似于命令行，一种类似于函数调用。" class="headerlink" title="和 RUN 指令一样，也有两种格式，一种类似于命令行，一种类似于函数调用。"></a>和 <code>RUN</code> 指令一样，也有两种格式，一种类似于命令行，一种类似于函数调用。</h5><h5 id="COPY-指令将从构建上下文目录中-的文件-目录复制到新的一层的镜像内的-位置。比如："><a href="#COPY-指令将从构建上下文目录中-的文件-目录复制到新的一层的镜像内的-位置。比如：" class="headerlink" title="COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。比如："></a><code>COPY</code> 指令将从构建上下文目录中 &lt;源路径&gt; 的文件/目录复制到新的一层的镜像内的 &lt;目标路径&gt; 位置。比如：</h5><figure class="highlight gradle"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs gradle"><span class="hljs-keyword">COPY</span> <span class="hljs-keyword">package</span>.json <span class="hljs-regexp">/usr/</span>src<span class="hljs-regexp">/app/</span><br></code></pre></td></tr></tbody></table></figure><h5 id="ADD-更高级的复制文件"><a href="#ADD-更高级的复制文件" class="headerlink" title="ADD 更高级的复制文件"></a><code>ADD</code> 更高级的复制文件</h5><h5 id="ADD-指令和-COPY-的格式和性质基本一致。但是在-COPY-基础上增加了一些功能。"><a href="#ADD-指令和-COPY-的格式和性质基本一致。但是在-COPY-基础上增加了一些功能。" class="headerlink" title="ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。"></a><code>ADD</code> 指令和 <code>COPY</code> 的格式和性质基本一致。但是在 <code>COPY</code> 基础上增加了一些功能。</h5><h5 id="比如-可以是一个-URL，这种情况下，Docker-引擎会试图去下载这个链接的文件放到-去。下载后的文件权限自动设置为-600，如果这并不是想要的权限，那么还需要增加额外的一层-RUN进行权限调整，另外，如果下载的是个压缩包，需要解压缩，也一样还需要额外的一层-RUN-指令进行解压缩。所以不如直接使用-RUN-指令，然后使用-wget-或者-curl-工具下载，处理权限、解压缩、然后清理无用文件更合理。因此，这个功能其实并不实用，而且不推荐使用。"><a href="#比如-可以是一个-URL，这种情况下，Docker-引擎会试图去下载这个链接的文件放到-去。下载后的文件权限自动设置为-600，如果这并不是想要的权限，那么还需要增加额外的一层-RUN进行权限调整，另外，如果下载的是个压缩包，需要解压缩，也一样还需要额外的一层-RUN-指令进行解压缩。所以不如直接使用-RUN-指令，然后使用-wget-或者-curl-工具下载，处理权限、解压缩、然后清理无用文件更合理。因此，这个功能其实并不实用，而且不推荐使用。" class="headerlink" title="比如 <源路径> 可以是一个 URL，这种情况下，Docker 引擎会试图去下载这个链接的文件放到 <目标路径> 去。下载后的文件权限自动设置为 600，如果这并不是想要的权限，那么还需要增加额外的一层 RUN进行权限调整，另外，如果下载的是个压缩包，需要解压缩，也一样还需要额外的一层 RUN 指令进行解压缩。所以不如直接使用 RUN 指令，然后使用 wget 或者 curl 工具下载，处理权限、解压缩、然后清理无用文件更合理。因此，这个功能其实并不实用，而且不推荐使用。"></a>比如 &lt;源路径&gt; 可以是一个 URL，这种情况下，<code>Docker</code> 引擎会试图去下载这个链接的文件放到 &lt;目标路径&gt; 去。下载后的文件权限自动设置为 600，如果这并不是想要的权限，那么还需要增加额外的一层 RUN进行权限调整，另外，如果下载的是个压缩包，需要解压缩，也一样还需要额外的一层 RUN 指令进行解压缩。所以不如直接使用 <code>RUN</code> 指令，然后使用 <code>wget</code> 或者 <code>curl</code> 工具下载，处理权限、解压缩、然后清理无用文件更合理。因此，这个功能其实并不实用，而且不推荐使用。</h5><h5 id="如果-为一个-tar-压缩文件的话，压缩格式为-gzip-bzip2-以及-xz-的情况下，ADD-指令将会自动解压缩这个压缩文件到-去。"><a href="#如果-为一个-tar-压缩文件的话，压缩格式为-gzip-bzip2-以及-xz-的情况下，ADD-指令将会自动解压缩这个压缩文件到-去。" class="headerlink" title="如果 <源路径> 为一个 tar 压缩文件的话，压缩格式为 gzip, bzip2 以及 xz 的情况下，ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去。"></a>如果 &lt;源路径&gt; 为一个 tar 压缩文件的话，压缩格式为 gzip, bzip2 以及 xz 的情况下，<code>ADD</code> 指令将会自动解压缩这个压缩文件到 &lt;目标路径&gt; 去。</h5><h5 id="在某些情况下，这个自动解压缩的功能非常有用，比如官方镜像-ubuntu-中："><a href="#在某些情况下，这个自动解压缩的功能非常有用，比如官方镜像-ubuntu-中：" class="headerlink" title="在某些情况下，这个自动解压缩的功能非常有用，比如官方镜像 ubuntu 中："></a>在某些情况下，这个自动解压缩的功能非常有用，比如官方镜像 <code>ubuntu</code> 中：</h5><figure class="highlight routeros"><table><tbody><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><code class="hljs routeros"><span class="hljs-keyword">FROM</span> scratch<br><span class="hljs-built_in">ADD</span> ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /<br><span class="hljs-built_in">..</span>.<br></code></pre></td></tr></tbody></table></figure><h5 id="但在某些情况下，如果我们真的是希望复制个压缩文件进去，而不解压缩，这时就不可以使用-ADD-命令了。"><a href="#但在某些情况下，如果我们真的是希望复制个压缩文件进去，而不解压缩，这时就不可以使用-ADD-命令了。" class="headerlink" title="但在某些情况下，如果我们真的是希望复制个压缩文件进去，而不解压缩，这时就不可以使用 ADD 命令了。"></a>但在某些情况下，如果我们真的是希望复制个压缩文件进去，而不解压缩，这时就不可以使用 <code>ADD</code> 命令了。</h5><h5 id="在-Docker-官方的最佳实践文档中要求，尽可能的使用-COPY，因为-COPY-的语义很明确，就是复制文件而已，而-ADD-则包含了更复杂的功能，其行为也不一定很清晰。最适合使用-ADD-的场合，就是所提及的需要自动解压缩的场合。"><a href="#在-Docker-官方的最佳实践文档中要求，尽可能的使用-COPY，因为-COPY-的语义很明确，就是复制文件而已，而-ADD-则包含了更复杂的功能，其行为也不一定很清晰。最适合使用-ADD-的场合，就是所提及的需要自动解压缩的场合。" class="headerlink" title="在 Docker 官方的最佳实践文档中要求，尽可能的使用 COPY，因为 COPY 的语义很明确，就是复制文件而已，而 ADD 则包含了更复杂的功能，其行为也不一定很清晰。最适合使用 ADD 的场合，就是所提及的需要自动解压缩的场合。"></a>在 <code>Docker</code> 官方的最佳实践文档中要求，尽可能的使用 <code>COPY</code>，因为 <code>COPY</code> 的语义很明确，就是复制文件而已，而 ADD 则包含了更复杂的功能，其行为也不一定很清晰。最适合使用 <code>ADD</code> 的场合，就是所提及的需要自动解压缩的场合。</h5><h5 id="另外需要注意的是，ADD-指令会令镜像构建缓存失效，从而可能会令镜像构建变得比较缓慢。"><a href="#另外需要注意的是，ADD-指令会令镜像构建缓存失效，从而可能会令镜像构建变得比较缓慢。" class="headerlink" title="另外需要注意的是，ADD 指令会令镜像构建缓存失效，从而可能会令镜像构建变得比较缓慢。"></a>另外需要注意的是，ADD 指令会令镜像构建缓存失效，从而可能会令镜像构建变得比较缓慢。</h5><h5 id="因此在-COPY-和-ADD-指令中选择的时候，可以遵循这样的原则，所有的文件复制均使用-COPY-指令，仅在需要自动解压缩的场合使用-ADD。"><a href="#因此在-COPY-和-ADD-指令中选择的时候，可以遵循这样的原则，所有的文件复制均使用-COPY-指令，仅在需要自动解压缩的场合使用-ADD。" class="headerlink" title="因此在 COPY 和 ADD 指令中选择的时候，可以遵循这样的原则，所有的文件复制均使用 COPY 指令，仅在需要自动解压缩的场合使用 ADD。"></a>因此在 <code>COPY</code> 和 <code>ADD</code> 指令中选择的时候，可以遵循这样的原则，所有的文件复制均使用 <code>COPY</code> 指令，仅在需要自动解压缩的场合使用 <code>ADD</code>。</h5><h5 id="CMD-容器启动命令"><a href="#CMD-容器启动命令" class="headerlink" title="CMD 容器启动命令"></a><code>CMD</code> 容器启动命令</h5><h5 id="CMD-指令就是用于指定默认的容器主进程的启动命令的。"><a href="#CMD-指令就是用于指定默认的容器主进程的启动命令的。" class="headerlink" title="CMD 指令就是用于指定默认的容器主进程的启动命令的。"></a><code>CMD</code> 指令就是用于指定默认的容器主进程的启动命令的。</h5><h5 id="CMD-指令的格式和-RUN-相似，也是两种格式："><a href="#CMD-指令的格式和-RUN-相似，也是两种格式：" class="headerlink" title="CMD 指令的格式和 RUN 相似，也是两种格式："></a><code>CMD</code> 指令的格式和 RUN 相似，也是两种格式：</h5><h5 id="shell-格式：CMD"><a href="#shell-格式：CMD" class="headerlink" title="shell 格式：CMD <命令>"></a><code>shell</code> 格式：<code>CMD</code> &lt;命令&gt;</h5><h5 id="exec-格式：CMD-“可执行文件”-“参数1”-“参数2”…"><a href="#exec-格式：CMD-“可执行文件”-“参数1”-“参数2”…" class="headerlink" title="exec 格式：CMD [“可执行文件”, “参数1”, “参数2”…]"></a><code>exec</code> 格式：<code>CMD</code> [“可执行文件”, “参数1”, “参数2”…]</h5><h5 id="参数列表格式：CMD-“参数1”-“参数2”…-。在指定了-ENTRYPOINT-指令后，用-CMD-指定具体的参数。"><a href="#参数列表格式：CMD-“参数1”-“参数2”…-。在指定了-ENTRYPOINT-指令后，用-CMD-指定具体的参数。" class="headerlink" title="参数列表格式：CMD [“参数1”, “参数2”…]。在指定了 ENTRYPOINT 指令后，用 CMD 指定具体的参数。"></a>参数列表格式：<code>CMD</code> [“参数1”, “参数2”…]。在指定了 <code>ENTRYPOINT</code> 指令后，用 <code>CMD</code> 指定具体的参数。</h5><h5 id="在运行时可以指定新的命令来替代镜像设置中的这个默认命令，比如，ubuntu-镜像默认的-CMD-是-bin-bash，如果我们直接-docker-run-it-ubuntu-的话，会直接进入-bash。我们也可以在运行时指定运行别的命令，如-docker-run-it-ubuntu-cat-etc-os-release。这就是用-cat-etc-os-release-命令替换了默认的-bin-bash-命令了，输出了系统版本信息。"><a href="#在运行时可以指定新的命令来替代镜像设置中的这个默认命令，比如，ubuntu-镜像默认的-CMD-是-bin-bash，如果我们直接-docker-run-it-ubuntu-的话，会直接进入-bash。我们也可以在运行时指定运行别的命令，如-docker-run-it-ubuntu-cat-etc-os-release。这就是用-cat-etc-os-release-命令替换了默认的-bin-bash-命令了，输出了系统版本信息。" class="headerlink" title="在运行时可以指定新的命令来替代镜像设置中的这个默认命令，比如，ubuntu 镜像默认的 CMD 是 /bin/bash，如果我们直接 docker run -it ubuntu 的话，会直接进入 bash。我们也可以在运行时指定运行别的命令，如 docker run -it ubuntu cat /etc/os-release。这就是用 cat /etc/os-release 命令替换了默认的 /bin/bash 命令了，输出了系统版本信息。"></a>在运行时可以指定新的命令来替代镜像设置中的这个默认命令，比如，<code>ubuntu</code> 镜像默认的 <code>CMD</code> 是 <code>/bin/bash</code>，如果我们直接 <code>docker run -it ubuntu</code> 的话，会直接进入 <code>bash</code>。我们也可以在运行时指定运行别的命令，如 <code>docker run -it ubuntu cat /etc/os-release</code>。这就是用 <code>cat /etc/os-release </code>命令替换了默认的 <code>/bin/bash</code> 命令了，输出了系统版本信息。</h5><h5 id="在指令格式上，一般推荐使用-exec-格式，这类格式在解析时会被解析为-JSON-数组，因此一定要使用双引号-“，而不要使用单引号。"><a href="#在指令格式上，一般推荐使用-exec-格式，这类格式在解析时会被解析为-JSON-数组，因此一定要使用双引号-“，而不要使用单引号。" class="headerlink" title="在指令格式上，一般推荐使用 exec 格式，这类格式在解析时会被解析为 JSON 数组，因此一定要使用双引号 “，而不要使用单引号。"></a>在指令格式上，一般推荐使用 <code>exec</code> 格式，这类格式在解析时会被解析为 <code>JSON</code> 数组，因此一定要使用双引号 “，而不要使用单引号。</h5><h5 id="如果使用-shell-格式的话，实际的命令会被包装为-sh-c-的参数的形式进行执行。比如："><a href="#如果使用-shell-格式的话，实际的命令会被包装为-sh-c-的参数的形式进行执行。比如：" class="headerlink" title="如果使用 shell 格式的话，实际的命令会被包装为 sh -c 的参数的形式进行执行。比如："></a>如果使用 <code>shell</code> 格式的话，实际的命令会被包装为 <code>sh -c</code> 的参数的形式进行执行。比如：</h5><figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">CMD</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-variable">$HOME</span></span><br></code></pre></td></tr></tbody></table></figure><h5 id="在实际执行中，会将其变更为："><a href="#在实际执行中，会将其变更为：" class="headerlink" title="在实际执行中，会将其变更为："></a>在实际执行中，会将其变更为：</h5><figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">CMD</span><span class="language-bash"> [ <span class="hljs-string">"sh"</span>, <span class="hljs-string">"-c"</span>, <span class="hljs-string">"echo <span class="hljs-variable">$HOME</span>"</span> ]</span><br></code></pre></td></tr></tbody></table></figure><h5 id="所以如果使用shell格式会导致容器莫名退出，因为实际上执行的事sh命令，而sh命令执行完时候容器也就没有存在的意义。"><a href="#所以如果使用shell格式会导致容器莫名退出，因为实际上执行的事sh命令，而sh命令执行完时候容器也就没有存在的意义。" class="headerlink" title="所以如果使用shell格式会导致容器莫名退出，因为实际上执行的事sh命令，而sh命令执行完时候容器也就没有存在的意义。"></a>所以如果使用shell格式会导致容器莫名退出，因为实际上执行的事sh命令，而sh命令执行完时候容器也就没有存在的意义。</h5><h4 id="ENTRYPOINT-入口点"><a href="#ENTRYPOINT-入口点" class="headerlink" title="ENTRYPOINT 入口点"></a><code>ENTRYPOINT</code> 入口点</h4><h5 id="ENTRYPOINT-的格式和-RUN-指令格式一样，分为-exec-格式和-shell-格式。"><a href="#ENTRYPOINT-的格式和-RUN-指令格式一样，分为-exec-格式和-shell-格式。" class="headerlink" title="ENTRYPOINT 的格式和 RUN 指令格式一样，分为 exec 格式和 shell 格式。"></a><code>ENTRYPOINT</code> 的格式和 RUN 指令格式一样，分为 <code>exec</code> 格式和 <code>shell</code> 格式。</h5><h5 id="ENTRYPOINT-的目的和-CMD-一样，都是在指定容器启动程序及参数。ENTRYPOINT-在运行时也可以替代，不过比-CMD-要略显繁琐，需要通过-docker-run-的参数-entrypoint-来指定。"><a href="#ENTRYPOINT-的目的和-CMD-一样，都是在指定容器启动程序及参数。ENTRYPOINT-在运行时也可以替代，不过比-CMD-要略显繁琐，需要通过-docker-run-的参数-entrypoint-来指定。" class="headerlink" title="ENTRYPOINT 的目的和 CMD 一样，都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代，不过比 CMD 要略显繁琐，需要通过 docker run 的参数 --entrypoint 来指定。"></a><code>ENTRYPOINT</code> 的目的和 <code>CMD</code> 一样，都是在指定容器启动程序及参数。<code>ENTRYPOINT</code> 在运行时也可以替代，不过比 <code>CMD</code> 要略显繁琐，需要通过 <code>docker run</code> 的参数 <code>--entrypoint</code> 来指定。</h5><h5 id="当指定了-ENTRYPOINT-后，CMD-的含义就发生了改变，不再是直接的运行其命令，而是将-CMD-的内容作为参数传给-ENTRYPOINT-指令，换句话说实际执行时，将变为："><a href="#当指定了-ENTRYPOINT-后，CMD-的含义就发生了改变，不再是直接的运行其命令，而是将-CMD-的内容作为参数传给-ENTRYPOINT-指令，换句话说实际执行时，将变为：" class="headerlink" title="当指定了 ENTRYPOINT 后，CMD 的含义就发生了改变，不再是直接的运行其命令，而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令，换句话说实际执行时，将变为："></a>当指定了 <code>ENTRYPOINT</code> 后，<code>CMD</code> 的含义就发生了改变，不再是直接的运行其命令，而是将 <code>CMD</code> 的内容作为参数传给 <code>ENTRYPOINT</code> 指令，换句话说实际执行时，将变为：</h5><figure class="highlight xml"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">ENTRYPOINT</span>&gt;</span> "<span class="hljs-tag">&lt;<span class="hljs-name">CMD</span>&gt;</span>"<br></code></pre></td></tr></tbody></table></figure><h5 id="这个指令非常有用，例如可以把命令后面的参数传进来或启动容器前准备一些环境然后执行启动命令（通过脚本exec-）。"><a href="#这个指令非常有用，例如可以把命令后面的参数传进来或启动容器前准备一些环境然后执行启动命令（通过脚本exec-）。" class="headerlink" title="这个指令非常有用，例如可以把命令后面的参数传进来或启动容器前准备一些环境然后执行启动命令（通过脚本exec &quot;$@&quot;）。"></a>这个指令非常有用，例如可以把命令后面的参数传进来或启动容器前准备一些环境然后执行启动命令（通过脚本<code>exec "$@"</code>）。</h5><h4 id="ENV-设置环境变量"><a href="#ENV-设置环境变量" class="headerlink" title="ENV 设置环境变量"></a><code>ENV</code> 设置环境变量</h4><h5 id="格式有两种："><a href="#格式有两种：" class="headerlink" title="格式有两种："></a>格式有两种：</h5><figure class="highlight xml"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs xml">ENV <span class="hljs-tag">&lt;<span class="hljs-name">key</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">value</span>&gt;</span><br>ENV <span class="hljs-tag">&lt;<span class="hljs-name">key1</span>&gt;</span>=<span class="hljs-tag">&lt;<span class="hljs-name">value1</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">key2</span>&gt;</span>=<span class="hljs-tag">&lt;<span class="hljs-name">value2</span>&gt;</span>...<br></code></pre></td></tr></tbody></table></figure><h5 id="这个指令很简单，就是设置环境变量而已，无论是后面的其它指令，如-RUN，还是运行时的应用，都可以直接使用这里定义的环境变量。"><a href="#这个指令很简单，就是设置环境变量而已，无论是后面的其它指令，如-RUN，还是运行时的应用，都可以直接使用这里定义的环境变量。" class="headerlink" title="这个指令很简单，就是设置环境变量而已，无论是后面的其它指令，如 RUN，还是运行时的应用，都可以直接使用这里定义的环境变量。"></a>这个指令很简单，就是设置环境变量而已，无论是后面的其它指令，如 RUN，还是运行时的应用，都可以直接使用这里定义的环境变量。</h5><figure class="highlight dockerfile"><table><tbody><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><code class="hljs dockerfile">ex：<br><br><span class="hljs-keyword">ENV</span> NODE_VERSION <span class="hljs-number">6</span><br>...<br><span class="hljs-keyword">RUN</span><span class="language-bash"> curl -sL https://deb.nodesource.com/setup_<span class="hljs-variable">$NODE_VERSION</span>.x | bash - &amp;&amp; \</span><br><span class="language-bash">...</span><br></code></pre></td></tr></tbody></table></figure><h4 id="ARG-构建参数"><a href="#ARG-构建参数" class="headerlink" title="ARG 构建参数"></a><code>ARG</code> 构建参数</h4><p>#####格式：<code>ARG</code> &lt;参数名&gt;[=&lt;默认值&gt;]</p><h5 id="构建参数和-ENV-的效果一样，都是设置环境变量。所不同的是，ARG-所设置的构建环境的环境变量，在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用-ARG-保存密码之类的信息，因为-docker-history-还是可以看到所有值的。"><a href="#构建参数和-ENV-的效果一样，都是设置环境变量。所不同的是，ARG-所设置的构建环境的环境变量，在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用-ARG-保存密码之类的信息，因为-docker-history-还是可以看到所有值的。" class="headerlink" title="构建参数和 ENV 的效果一样，都是设置环境变量。所不同的是，ARG 所设置的构建环境的环境变量，在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息，因为 docker history 还是可以看到所有值的。"></a>构建参数和 <code>ENV</code> 的效果一样，都是设置环境变量。所不同的是，<code>ARG</code> 所设置的构建环境的环境变量，在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 <code>ARG</code> 保存密码之类的信息，因为 <code>docker history</code> 还是可以看到所有值的。</h5><h5 id="Dockerfile-中的-ARG-指令是定义参数名称，以及定义其默认值。该默认值可以在构建命令-docker-build-中用-build-arg-来覆盖。"><a href="#Dockerfile-中的-ARG-指令是定义参数名称，以及定义其默认值。该默认值可以在构建命令-docker-build-中用-build-arg-来覆盖。" class="headerlink" title="Dockerfile 中的 ARG 指令是定义参数名称，以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。"></a><code>Dockerfile</code> 中的 <code>ARG</code> 指令是定义参数名称，以及定义其默认值。该默认值可以在构建命令 <code>docker build</code> 中用 <code>--build-arg</code> &lt;参数名&gt;=&lt;值&gt; 来覆盖。</h5><h5 id="在-1-13-之前的版本，要求-build-arg-中的参数名，必须在-Dockerfile-中用-ARG-定义过了，换句话说，就是-build-arg-指定的参数，必须在-Dockerfile-中使用了。如果对应参数没有被使用，则会报错退出构建。从-1-13-开始，这种严格的限制被放开，不再报错退出，而是显示警告信息，并继续构建。这对于使用-CI-系统，用同样的构建流程构建不同的-Dockerfile-的时候比较有帮助，避免构建命令必须根据每个-Dockerfile-的内容修改。"><a href="#在-1-13-之前的版本，要求-build-arg-中的参数名，必须在-Dockerfile-中用-ARG-定义过了，换句话说，就是-build-arg-指定的参数，必须在-Dockerfile-中使用了。如果对应参数没有被使用，则会报错退出构建。从-1-13-开始，这种严格的限制被放开，不再报错退出，而是显示警告信息，并继续构建。这对于使用-CI-系统，用同样的构建流程构建不同的-Dockerfile-的时候比较有帮助，避免构建命令必须根据每个-Dockerfile-的内容修改。" class="headerlink" title="在 1.13 之前的版本，要求 --build-arg 中的参数名，必须在 Dockerfile 中用 ARG 定义过了，换句话说，就是 --build-arg 指定的参数，必须在 Dockerfile 中使用了。如果对应参数没有被使用，则会报错退出构建。从 1.13 开始，这种严格的限制被放开，不再报错退出，而是显示警告信息，并继续构建。这对于使用 CI 系统，用同样的构建流程构建不同的 Dockerfile 的时候比较有帮助，避免构建命令必须根据每个 Dockerfile 的内容修改。"></a>在 1.13 之前的版本，要求 <code>--build-arg</code> 中的参数名，必须在 <code>Dockerfile</code> 中用 <code>ARG</code> 定义过了，换句话说，就是 <code>--build-arg</code> 指定的参数，必须在 <code>Dockerfile</code> 中使用了。如果对应参数没有被使用，则会报错退出构建。从 1.13 开始，这种严格的限制被放开，不再报错退出，而是显示警告信息，并继续构建。这对于使用 CI 系统，用同样的构建流程构建不同的 <code>Dockerfile</code> 的时候比较有帮助，避免构建命令必须根据每个 <code>Dockerfile</code> 的内容修改。</h5><h4 id="VOLUME-定义匿名卷"><a href="#VOLUME-定义匿名卷" class="headerlink" title="VOLUME 定义匿名卷"></a><code>VOLUME</code> 定义匿名卷</h4><p>格式为：</p><figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">VOLUME</span><span class="language-bash"> [<span class="hljs-string">"&lt;路径1&gt;"</span>, <span class="hljs-string">"&lt;路径2&gt;"</span>...]</span><br><span class="hljs-keyword">VOLUME</span><span class="language-bash"> &lt;路径&gt;</span><br></code></pre></td></tr></tbody></table></figure><h5 id="之前我们说过，容器运行时应该尽量保持容器存储层不发生写操作，对于数据库类需要保存动态数据的应用，其数据库文件应该保存于卷-volume-中，后面的章节我们会进一步介绍-Docker-卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷，在-Dockerfile-中，我们可以事先指定某些目录挂载为匿名卷，这样在运行时如果用户不指定挂载，其应用也可以正常运行，不会向容器存储层写入大量数据。"><a href="#之前我们说过，容器运行时应该尽量保持容器存储层不发生写操作，对于数据库类需要保存动态数据的应用，其数据库文件应该保存于卷-volume-中，后面的章节我们会进一步介绍-Docker-卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷，在-Dockerfile-中，我们可以事先指定某些目录挂载为匿名卷，这样在运行时如果用户不指定挂载，其应用也可以正常运行，不会向容器存储层写入大量数据。" class="headerlink" title="之前我们说过，容器运行时应该尽量保持容器存储层不发生写操作，对于数据库类需要保存动态数据的应用，其数据库文件应该保存于卷(volume)中，后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷，在 Dockerfile 中，我们可以事先指定某些目录挂载为匿名卷，这样在运行时如果用户不指定挂载，其应用也可以正常运行，不会向容器存储层写入大量数据。"></a>之前我们说过，容器运行时应该尽量保持容器存储层不发生写操作，对于数据库类需要保存动态数据的应用，其数据库文件应该保存于卷(volume)中，后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷，在 <code>Dockerfile</code> 中，我们可以事先指定某些目录挂载为匿名卷，这样在运行时如果用户不指定挂载，其应用也可以正常运行，不会向容器存储层写入大量数据。</h5><figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">VOLUME</span><span class="language-bash"> /data</span><br></code></pre></td></tr></tbody></table></figure><h5 id="这里的-data-目录就会在运行时自动挂载为匿名卷，任何向-data-中写入的信息都不会记录进容器存储层，从而保证了容器存储层的无状态化。当然，运行时可以覆盖这个挂载设置。比如："><a href="#这里的-data-目录就会在运行时自动挂载为匿名卷，任何向-data-中写入的信息都不会记录进容器存储层，从而保证了容器存储层的无状态化。当然，运行时可以覆盖这个挂载设置。比如：" class="headerlink" title="这里的 /data 目录就会在运行时自动挂载为匿名卷，任何向 /data 中写入的信息都不会记录进容器存储层，从而保证了容器存储层的无状态化。当然，运行时可以覆盖这个挂载设置。比如："></a>这里的 <code>/data</code> 目录就会在运行时自动挂载为匿名卷，任何向 <code>/data</code> 中写入的信息都不会记录进容器存储层，从而保证了容器存储层的无状态化。当然，运行时可以覆盖这个挂载设置。比如：</h5><figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile">docker <span class="hljs-keyword">run</span><span class="language-bash"> -d -v mydata:/data xxxx</span><br></code></pre></td></tr></tbody></table></figure><h5 id="在这行命令中，就使用了-mydata-这个命名卷挂载到了-data-这个位置，替代了-Dockerfile-中定义的匿名卷的挂载配置。"><a href="#在这行命令中，就使用了-mydata-这个命名卷挂载到了-data-这个位置，替代了-Dockerfile-中定义的匿名卷的挂载配置。" class="headerlink" title="在这行命令中，就使用了 mydata 这个命名卷挂载到了 /data 这个位置，替代了 Dockerfile 中定义的匿名卷的挂载配置。"></a>在这行命令中，就使用了<code> mydata</code> 这个命名卷挂载到了 <code>/data</code> 这个位置，替代了 <code>Dockerfile</code> 中定义的匿名卷的挂载配置。</h5><h4 id="EXPOSE-声明端口"><a href="#EXPOSE-声明端口" class="headerlink" title="EXPOSE 声明端口"></a><code>EXPOSE</code> 声明端口</h4><h5 id="格式为-EXPOSE-…-。"><a href="#格式为-EXPOSE-…-。" class="headerlink" title="格式为 EXPOSE <端口1> [<端口2>…]。"></a>格式为 <code>EXPOSE</code> &lt;端口1&gt; [&lt;端口2&gt;…]。</h5><h5 id="EXPOSE-指令是声明运行时容器提供服务端口，这只是一个声明，在运行时并不会因为这个声明应用就会开启这个端口的服务。在-Dockerfile-中写入这样的声明有两个好处，一个是帮助镜像使用者理解这个镜像服务的守护端口，以方便配置映射；另一个用处则是在运行时使用随机端口映射时，也就是-docker-run-P时，会自动随机映射-EXPOSE-的端口。"><a href="#EXPOSE-指令是声明运行时容器提供服务端口，这只是一个声明，在运行时并不会因为这个声明应用就会开启这个端口的服务。在-Dockerfile-中写入这样的声明有两个好处，一个是帮助镜像使用者理解这个镜像服务的守护端口，以方便配置映射；另一个用处则是在运行时使用随机端口映射时，也就是-docker-run-P时，会自动随机映射-EXPOSE-的端口。" class="headerlink" title="EXPOSE 指令是声明运行时容器提供服务端口，这只是一个声明，在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处，一个是帮助镜像使用者理解这个镜像服务的守护端口，以方便配置映射；另一个用处则是在运行时使用随机端口映射时，也就是 docker run -P时，会自动随机映射 EXPOSE 的端口。"></a><code>EXPOSE</code> 指令是声明运行时容器提供服务端口，这只是一个声明，在运行时并不会因为这个声明应用就会开启这个端口的服务。在 <code>Dockerfile</code> 中写入这样的声明有两个好处，一个是帮助镜像使用者理解这个镜像服务的守护端口，以方便配置映射；另一个用处则是在运行时使用随机端口映射时，也就是 <code>docker run -P</code>时，会自动随机映射 <code>EXPOSE</code> 的端口。</h5><h5 id="此外，在早期-Docker-版本中还有一个特殊的用处。以前所有容器都运行于默认桥接网络中，因此所有容器互相之间都可以直接访问，这样存在一定的安全性问题。于是有了一个-Docker-引擎参数-icc-false，当指定该参数后，容器间将默认无法互访，除非互相间使用了-–links-参数的容器才可以互通，并且只有镜像中-EXPOSE-所声明的端口才可以被访问。这个-icc-false-的用法，在引入了-docker-network后已经基本不用了，通过自定义网络可以很轻松的实现容器间的互联与隔离。"><a href="#此外，在早期-Docker-版本中还有一个特殊的用处。以前所有容器都运行于默认桥接网络中，因此所有容器互相之间都可以直接访问，这样存在一定的安全性问题。于是有了一个-Docker-引擎参数-icc-false，当指定该参数后，容器间将默认无法互访，除非互相间使用了-–links-参数的容器才可以互通，并且只有镜像中-EXPOSE-所声明的端口才可以被访问。这个-icc-false-的用法，在引入了-docker-network后已经基本不用了，通过自定义网络可以很轻松的实现容器间的互联与隔离。" class="headerlink" title="此外，在早期 Docker 版本中还有一个特殊的用处。以前所有容器都运行于默认桥接网络中，因此所有容器互相之间都可以直接访问，这样存在一定的安全性问题。于是有了一个 Docker 引擎参数 --icc=false，当指定该参数后，容器间将默认无法互访，除非互相间使用了 –links 参数的容器才可以互通，并且只有镜像中 EXPOSE 所声明的端口才可以被访问。这个 --icc=false 的用法，在引入了 docker network后已经基本不用了，通过自定义网络可以很轻松的实现容器间的互联与隔离。"></a>此外，在早期 <code>Docker</code> 版本中还有一个特殊的用处。以前所有容器都运行于默认桥接网络中，因此所有容器互相之间都可以直接访问，这样存在一定的安全性问题。于是有了一个 <code>Docker</code> 引擎参数 <code>--icc=false</code>，当指定该参数后，容器间将默认无法互访，除非互相间使用了 –links 参数的容器才可以互通，并且只有镜像中 <code>EXPOSE</code> 所声明的端口才可以被访问。这个 <code>--icc=false</code> 的用法，在引入了 <code>docker network</code>后已经基本不用了，通过自定义网络可以很轻松的实现容器间的互联与隔离。</h5><h5 id="要将-EXPOSE-和在运行时使用-p-区分开来。-p，是映射宿主端口和容器端口，换句话说，就是将容器的对应端口服务公开给外界访问，而-EXPOSE-仅仅是声明容器打算使用什么端口而已，并不会自动在宿主进行端口映射。"><a href="#要将-EXPOSE-和在运行时使用-p-区分开来。-p，是映射宿主端口和容器端口，换句话说，就是将容器的对应端口服务公开给外界访问，而-EXPOSE-仅仅是声明容器打算使用什么端口而已，并不会自动在宿主进行端口映射。" class="headerlink" title="要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。-p，是映射宿主端口和容器端口，换句话说，就是将容器的对应端口服务公开给外界访问，而 EXPOSE 仅仅是声明容器打算使用什么端口而已，并不会自动在宿主进行端口映射。"></a>要将 <code>EXPOSE</code> 和在运行时使用 <code>-p</code> &lt;宿主端口&gt;:&lt;容器端口&gt; 区分开来。<code>-p</code>，是映射宿主端口和容器端口，换句话说，就是将容器的对应端口服务公开给外界访问，而 <code>EXPOSE</code> 仅仅是声明容器打算使用什么端口而已，并不会自动在宿主进行端口映射。</h5><h4 id="WORKDIR-指定工作目录"><a href="#WORKDIR-指定工作目录" class="headerlink" title="WORKDIR 指定工作目录"></a><code>WORKDIR</code> 指定工作目录</h4><h5 id="格式为-WORKDIR-。"><a href="#格式为-WORKDIR-。" class="headerlink" title="格式为 WORKDIR <工作目录路径>。"></a>格式为 <code>WORKDIR</code> &lt;工作目录路径&gt;。</h5><h5 id="使用-WORKDIR-指令可以来指定工作目录（或者称为当前目录），以后各层的当前目录就被改为指定的目录，如该目录不存在，WORKDIR-会帮你建立目录。"><a href="#使用-WORKDIR-指令可以来指定工作目录（或者称为当前目录），以后各层的当前目录就被改为指定的目录，如该目录不存在，WORKDIR-会帮你建立目录。" class="headerlink" title="使用 WORKDIR 指令可以来指定工作目录（或者称为当前目录），以后各层的当前目录就被改为指定的目录，如该目录不存在，WORKDIR 会帮你建立目录。"></a>使用 <code>WORKDIR</code> 指令可以来指定工作目录（或者称为当前目录），以后各层的当前目录就被改为指定的目录，如该目录不存在，<code>WORKDIR</code> 会帮你建立目录。</h5><h5 id="之前提到一些初学者常犯的错误是把-Dockerfile-等同于-Shell-脚本来书写，这种错误的理解还可能会导致出现下面这样的错误："><a href="#之前提到一些初学者常犯的错误是把-Dockerfile-等同于-Shell-脚本来书写，这种错误的理解还可能会导致出现下面这样的错误：" class="headerlink" title="之前提到一些初学者常犯的错误是把 Dockerfile 等同于 Shell 脚本来书写，这种错误的理解还可能会导致出现下面这样的错误："></a>之前提到一些初学者常犯的错误是把 <code>Dockerfile</code> 等同于 <code>Shell</code> 脚本来书写，这种错误的理解还可能会导致出现下面这样的错误：</h5><figure class="highlight dockerfile"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs dockerfile"><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">cd</span> /app</span><br><span class="hljs-keyword">RUN</span><span class="language-bash"> <span class="hljs-built_in">echo</span> <span class="hljs-string">"hello"</span> &gt; world.txt</span><br></code></pre></td></tr></tbody></table></figure><h5 id="如果将这个-Dockerfile-进行构建镜像运行后，会发现找不到-app-world-txt-文件，或者其内容不是-hello。原因其实很简单，在-Shell-中，连续两行是同一个进程执行环境，因此前一个命令修改的内存状态，会直接影响后一个命令；而在-Dockerfile-中，这两行-RUN-命令的执行环境根本不同，是两个完全不同的容器。这就是对-Dokerfile-构建分层存储的概念不了解所导致的错误。"><a href="#如果将这个-Dockerfile-进行构建镜像运行后，会发现找不到-app-world-txt-文件，或者其内容不是-hello。原因其实很简单，在-Shell-中，连续两行是同一个进程执行环境，因此前一个命令修改的内存状态，会直接影响后一个命令；而在-Dockerfile-中，这两行-RUN-命令的执行环境根本不同，是两个完全不同的容器。这就是对-Dokerfile-构建分层存储的概念不了解所导致的错误。" class="headerlink" title="如果将这个 Dockerfile 进行构建镜像运行后，会发现找不到 /app/world.txt 文件，或者其内容不是 hello。原因其实很简单，在 Shell 中，连续两行是同一个进程执行环境，因此前一个命令修改的内存状态，会直接影响后一个命令；而在 Dockerfile 中，这两行 RUN 命令的执行环境根本不同，是两个完全不同的容器。这就是对 Dokerfile 构建分层存储的概念不了解所导致的错误。"></a>如果将这个 <code>Dockerfile</code> 进行构建镜像运行后，会发现找不到 <code>/app/world.txt</code> 文件，或者其内容不是 <code>hello</code>。原因其实很简单，在 <code>Shell</code> 中，连续两行是同一个进程执行环境，因此前一个命令修改的内存状态，会直接影响后一个命令；而在 <code>Dockerfile</code> 中，这两行 <code>RUN</code> 命令的执行环境根本不同，是两个完全不同的容器。这就是对 <code>Dokerfile</code> 构建分层存储的概念不了解所导致的错误。</h5><h5 id="之前说过每一个-RUN-都是启动一个容器、执行命令、然后提交存储层文件变更。第一层-RUN-cd-app-的执行仅仅是当前进程的工作目录变更，一个内存上的变化而已，其结果不会造成任何文件变更。而到第二层的时候，启动的是一个全新的容器，跟第一层的容器更完全没关系，自然不可能继承前一层构建过程中的内存变化。"><a href="#之前说过每一个-RUN-都是启动一个容器、执行命令、然后提交存储层文件变更。第一层-RUN-cd-app-的执行仅仅是当前进程的工作目录变更，一个内存上的变化而已，其结果不会造成任何文件变更。而到第二层的时候，启动的是一个全新的容器，跟第一层的容器更完全没关系，自然不可能继承前一层构建过程中的内存变化。" class="headerlink" title="之前说过每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 RUN cd /app 的执行仅仅是当前进程的工作目录变更，一个内存上的变化而已，其结果不会造成任何文件变更。而到第二层的时候，启动的是一个全新的容器，跟第一层的容器更完全没关系，自然不可能继承前一层构建过程中的内存变化。"></a>之前说过每一个 <code>RUN</code> 都是启动一个容器、执行命令、然后提交存储层文件变更。第一层 <code>RUN cd /app</code> 的执行仅仅是当前进程的工作目录变更，一个内存上的变化而已，其结果不会造成任何文件变更。而到第二层的时候，启动的是一个全新的容器，跟第一层的容器更完全没关系，自然不可能继承前一层构建过程中的内存变化。</h5><h5 id="因此如果需要改变以后各层的工作目录的位置，那么应该使用-WORKDIR-指令。"><a href="#因此如果需要改变以后各层的工作目录的位置，那么应该使用-WORKDIR-指令。" class="headerlink" title="因此如果需要改变以后各层的工作目录的位置，那么应该使用 WORKDIR 指令。"></a>因此如果需要改变以后各层的工作目录的位置，那么应该使用 <code>WORKDIR</code> 指令。</h5><h4 id="USER-指定当前用户"><a href="#USER-指定当前用户" class="headerlink" title="USER 指定当前用户"></a><code>USER</code> 指定当前用户</h4><h5 id="格式：USER"><a href="#格式：USER" class="headerlink" title="格式：USER <用户名>"></a>格式：<code>USER</code> &lt;用户名&gt;</h5><h5 id="USER-指令和-WORKDIR-相似，都是改变环境状态并影响以后的层。WORKDIR-是改变工作目录，USER则是改变之后层的执行-RUN-CMD-以及-ENTRYPOINT-这类命令的身份。"><a href="#USER-指令和-WORKDIR-相似，都是改变环境状态并影响以后的层。WORKDIR-是改变工作目录，USER则是改变之后层的执行-RUN-CMD-以及-ENTRYPOINT-这类命令的身份。" class="headerlink" title="USER 指令和 WORKDIR 相似，都是改变环境状态并影响以后的层。WORKDIR 是改变工作目录，USER则是改变之后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。"></a><code>USER</code> 指令和 <code>WORKDIR</code> 相似，都是改变环境状态并影响以后的层。<code>WORKDIR</code> 是改变工作目录，<code>USER</code>则是改变之后层的执行 <code>RUN</code>, <code>CMD</code> 以及 <code>ENTRYPOINT</code> 这类命令的身份。</h5><h5 id="当然，和-WORKDIR-一样，USER-只是帮助你切换到指定用户而已，这个用户必须是事先建立好的，否则无法切换。"><a href="#当然，和-WORKDIR-一样，USER-只是帮助你切换到指定用户而已，这个用户必须是事先建立好的，否则无法切换。" class="headerlink" title="当然，和 WORKDIR 一样，USER 只是帮助你切换到指定用户而已，这个用户必须是事先建立好的，否则无法切换。"></a>当然，和 <code>WORKDIR</code> 一样，USER 只是帮助你切换到指定用户而已，这个用户必须是事先建立好的，否则无法切换。</h5><figure class="highlight routeros"><table><tbody><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><code class="hljs routeros"><span class="hljs-built_in">RUN</span> groupadd -r redis &amp;&amp; useradd -r -g redis redis<span class="hljs-built_in"></span><br><span class="hljs-built_in">USER </span>redis<br><span class="hljs-built_in">RUN</span> [ <span class="hljs-string">"redis-server"</span> ]<br></code></pre></td></tr></tbody></table></figure><h4 id="踩坑"><a href="#踩坑" class="headerlink" title="踩坑"></a>踩坑</h4><h5 id="Dockerfile里也需要注意权限问题（nodejs7版本以上不能正常安装hexo，需要创建用户并制定权限去安装）"><a href="#Dockerfile里也需要注意权限问题（nodejs7版本以上不能正常安装hexo，需要创建用户并制定权限去安装）" class="headerlink" title="Dockerfile里也需要注意权限问题（nodejs7版本以上不能正常安装hexo，需要创建用户并制定权限去安装）"></a><code>Dockerfile</code>里也需要注意权限问题（<code>nodejs</code>7版本以上不能正常安装<code>hexo</code>，需要创建用户并制定权限去安装）</h5><h5 id="在docker容器里如果是root用户对挂载的文件进行了操作，那么实际上挂载文件的权限也变成了root的"><a href="#在docker容器里如果是root用户对挂载的文件进行了操作，那么实际上挂载文件的权限也变成了root的" class="headerlink" title="在docker容器里如果是root用户对挂载的文件进行了操作，那么实际上挂载文件的权限也变成了root的"></a>在<code>docker</code>容器里如果是<code>root</code>用户对挂载的文件进行了操作，那么实际上挂载文件的权限也变成了<code>root</code>的</h5><h5 id="使用attach进入容器，退出的时候容器也跟着退出了。。。囧"><a href="#使用attach进入容器，退出的时候容器也跟着退出了。。。囧" class="headerlink" title="使用attach进入容器，退出的时候容器也跟着退出了。。。囧"></a>使用<code>attach</code>进入容器，退出的时候容器也跟着退出了。。。囧</h5><h5 id="每一个RUN是一个新的shell"><a href="#每一个RUN是一个新的shell" class="headerlink" title="每一个RUN是一个新的shell"></a>每一个<code>RUN</code>是一个新的<code>shell</code></h5><h5 id="su-之前在启动脚本加了-，导致环境变量以及工作目录都变了"><a href="#su-之前在启动脚本加了-，导致环境变量以及工作目录都变了" class="headerlink" title="su -之前在启动脚本加了-，导致环境变量以及工作目录都变了"></a><code>su -</code>之前在启动脚本加了<code>-</code>，导致环境变量以及工作目录都变了</h5><h4 id="Hexo-Docker"><a href="#Hexo-Docker" class="headerlink" title="Hexo-Docker"></a><code>Hexo-Docker</code></h4><h5 id="最后献上踩坑写的Hexo-Dockerfile"><a href="#最后献上踩坑写的Hexo-Dockerfile" class="headerlink" title="最后献上踩坑写的Hexo Dockerfile:"></a>最后献上踩坑写的Hexo Dockerfile:</h5><figure class="highlight bash"><table><tbody><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><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 使用Ubuntu官方镜像</span><br><br>FROM ubuntu:latest<br><br><span class="hljs-comment"># 作者信息</span><br>MAINTAINER yangbingdong &lt;yangbingdong1994@gmail.com&gt;<br><br><span class="hljs-comment"># 设置环境变量，使用${变量名}取值</span><br>ENV \<br>    USER_NAME=hexo \<br>    NODE_VERSION=8.5.0 \<br>    NODE_DIR=/home/<span class="hljs-variable">${USER_NAME}</span>/nodejs<br><br><span class="hljs-comment"># 需要执行的命令，使用 `$$ \` 分割多行多个命令</span><br>RUN \<br>    <span class="hljs-comment"># 安装基本的依赖以及工具</span><br>    apt-get update -y &amp;&amp; \<br>    apt-get upgrade -y &amp;&amp; \<br>    apt-get install -y git &amp;&amp; \<br>    apt-get install -y curl &amp;&amp; \<br>    apt-get install -y libpng-dev &amp;&amp; \<br>    <span class="hljs-comment"># 清理不必要的垃圾</span><br>    apt-get clean &amp;&amp; \<br>    apt-get autoclean &amp;&amp; \<br>    <span class="hljs-built_in">rm</span> -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* &amp;&amp; \<br>    <span class="hljs-comment"># 创建hexo用户去安装hexo</span><br>    useradd -m -U <span class="hljs-variable">${USER_NAME}</span> &amp;&amp; \<br>    <span class="hljs-comment"># 创建nodejs目录</span><br>    <span class="hljs-built_in">mkdir</span> <span class="hljs-variable">${NODE_DIR}</span> &amp;&amp; \<br>    <span class="hljs-comment"># 将nodejs下载解压到对应目录</span><br>    curl -L https://nodejs.org/dist/v<span class="hljs-variable">${NODE_VERSION}</span>/node-v<span class="hljs-variable">${NODE_VERSION}</span>-linux-x64.tar.gz | tar xvzf - -C <span class="hljs-variable">${NODE_DIR}</span> --strip-components=1 &amp;&amp; \<br>    <span class="hljs-comment"># 把nodejs文件赋权给hexo用户</span><br>    <span class="hljs-built_in">chown</span> -R <span class="hljs-variable">${USER_NAME}</span>.<span class="hljs-variable">${USER_NAME}</span> <span class="hljs-variable">${NODE_DIR}</span> &amp;&amp; \<br>    <span class="hljs-comment"># 把node相关命令软连接到/usr/local/bin目录下以便我们使用</span><br>    <span class="hljs-built_in">ln</span> -s <span class="hljs-variable">${NODE_DIR}</span>/bin/node /usr/local/bin/node &amp;&amp; \<br>    <span class="hljs-built_in">ln</span> -s <span class="hljs-variable">${NODE_DIR}</span>/bin/npm /usr/local/bin/npm &amp;&amp; \<br>    <span class="hljs-comment"># 以hexo用户身份安装hexo-cli</span><br>    su - <span class="hljs-variable">${USER_NAME}</span> -c <span class="hljs-string">"npm install -g hexo-cli"</span> &amp;&amp; \<br>    <span class="hljs-comment"># 同样把hexo命令放到/usr/local/bin下</span><br>    <span class="hljs-built_in">ln</span> -s <span class="hljs-variable">${NODE_DIR}</span>/bin/hexo /usr/local/bin/hexo &amp;&amp; \<br>    <span class="hljs-comment"># 使用淘宝镜像</span><br>    npm config <span class="hljs-built_in">set</span> registry https://registry.npm.taobao.org/<br><br><span class="hljs-comment"># 切换到此目录</span><br>WORKDIR /home/<span class="hljs-variable">${USER_NAME}</span>/blog<br><br><span class="hljs-comment"># 可以挂载进来的卷（文件夹）</span><br>VOLUME [<span class="hljs-string">"/home/<span class="hljs-variable">${USER_NAME}</span>/blog"</span>, <span class="hljs-string">"/home/<span class="hljs-variable">${USER_NAME}</span>/.ssh"</span>]<br><br><span class="hljs-comment"># 暴露端口</span><br>EXPOSE 4000<br><br><span class="hljs-comment"># 把上下文中的docker-entrypoint.sh复制进来</span><br>COPY docker-entrypoint.sh /docker-entrypoint.sh<br><br><span class="hljs-comment"># 执行脚本</span><br>ENTRYPOINT [<span class="hljs-string">"/docker-entrypoint.sh"</span>]<br><br><span class="hljs-comment"># 这个...鸡肋操作</span><br>CMD [<span class="hljs-string">'/bin/bash'</span>]<br>docker-entrypoint.sh :<br><br><span class="hljs-comment">#!/bin/sh</span><br><br><span class="hljs-comment"># 发生异常回滚</span><br><span class="hljs-built_in">set</span> -e<br><br><span class="hljs-comment"># 设置git相关信息，不设置默认为博主的=.=</span><br>GIT_USER_NAME=<span class="hljs-variable">${GIT_USER_NAME:-yangbingdong}</span><br><br>GIT_USER_MAIL=<span class="hljs-variable">${GIT_USER_MAIL:-yangbingdong1994@gmail.com}</span><br><br><span class="hljs-comment"># 你想要的用户名</span><br>NEW_USER_NAME=<span class="hljs-variable">${NEW_USER_NAME:-ybd}</span><br><br><span class="hljs-comment"># 由于每次启动容器都会执行这个脚本，但这个只需要执行一次，在此标志一下</span><br><span class="hljs-keyword">if</span> [ $(git config --system user.name)x = <span class="hljs-variable">${GIT_USER_NAME}</span>x ]<br><span class="hljs-keyword">then</span><br>    su <span class="hljs-variable">${NEW_USER_NAME}</span><br><span class="hljs-keyword">else</span><br>    <span class="hljs-comment"># 修改用户名</span><br>    /usr/sbin/usermod -l <span class="hljs-variable">${NEW_USER_NAME}</span> <span class="hljs-variable">${USER_NAME}</span><br><br>    /usr/sbin/usermod -c <span class="hljs-variable">${NEW_USER_NAME}</span> <span class="hljs-variable">${NEW_USER_NAME}</span><br><br>    /usr/sbin/groupmod -n <span class="hljs-variable">${NEW_USER_NAME}</span> <span class="hljs-variable">${USER_NAME}</span><br><br>    <span class="hljs-built_in">chown</span> -R <span class="hljs-variable">${NEW_USER_NAME}</span>.<span class="hljs-variable">${NEW_USER_NAME}</span> /home/<span class="hljs-variable">${USER_NAME}</span>/blog<br><br>    <span class="hljs-built_in">chmod</span> -R 766 /home/<span class="hljs-variable">${USER_NAME}</span>/blog<br>    <br>    <span class="hljs-comment"># 设置git全局信息</span><br>    git config --system user.name <span class="hljs-variable">$GIT_USER_NAME</span><br><br>    git config --system user.email <span class="hljs-variable">$GIT_USER_MAIL</span><br><br>    su <span class="hljs-variable">${NEW_USER_NAME}</span><br><span class="hljs-keyword">fi</span><br><br><span class="hljs-comment"># 执行脚本之后的命令</span><br><span class="hljs-built_in">exec</span> <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span><br></code></pre></td></tr></tbody></table></figure><h5 id="源码：https-github-com-masteranthoneyd-docker-hexo"><a href="#源码：https-github-com-masteranthoneyd-docker-hexo" class="headerlink" title="源码：https://github.com/masteranthoneyd/docker-hexo"></a>源码：<a href="https://github.com/masteranthoneyd/docker-hexo">https://github.com/masteranthoneyd/docker-hexo</a></h5>]]></content>
    
    
    <summary type="html">&lt;h5 id=&quot;制作一个镜像可以使用docker-commit和定制Dockerfile，但推荐的是写Dockerfile。&quot;&gt;&lt;a href=&quot;#制作一个镜像可以使用docker-commit和定制Dockerfile，但推荐的是写Dockerfile。&quot; class=&quot;headerlink&quot; title=&quot;制作一个镜像可以使用docker commit和定制Dockerfile，但推荐的是写Dockerfile。&quot;&gt;&lt;/a&gt;制作一个镜像可以使用&lt;code&gt;docker commit&lt;/code&gt;和定制&lt;code&gt;Dockerfile&lt;/code&gt;，但推荐的是写&lt;code&gt;Dockerfile&lt;/code&gt;。&lt;/h5&gt;&lt;h5 id=&quot;因为docker-commit是一个暗箱操作，除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知，而且会加入一些没用的操作导致镜像臃肿。&quot;&gt;&lt;a href=&quot;#因为docker-commit是一个暗箱操作，除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知，而且会加入一些没用的操作导致镜像臃肿。&quot; class=&quot;headerlink&quot; title=&quot;因为docker commit是一个暗箱操作，除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知，而且会加入一些没用的操作导致镜像臃肿。&quot;&gt;&lt;/a&gt;因为&lt;code&gt;docker commit&lt;/code&gt;是一个暗箱操作，除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知，而且会加入一些没用的操作导致镜像臃肿。&lt;/h5&gt;</summary>
    
    
    
    
  </entry>
  
</feed>
