<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>首页 on 12factor</title>
    <link>https://cncfstack.com/p/12factor/</link>
    <description>Recent content in 首页 on 12factor</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Fri, 20 Oct 2023 10:00:00 +0800</lastBuildDate>
    <atom:link href="https://cncfstack.com/p/12factor/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>HelmChart 仓库</title>
      <link>https://cncfstack.com/p/12factor/helmchart/</link>
      <pubDate>Fri, 20 Oct 2023 10:00:00 +0800</pubDate>
      <guid>https://cncfstack.com/p/12factor/helmchart/</guid>
      <description>&lt;div id=&#34;helmchart-container&#34;&gt;&#xA;  &lt;div class=&#34;charts-container&#34;&gt;&#xA;    &lt;div class=&#34;loading&#34;&gt;加载中...&lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;div class=&#34;pagination-wrapper&#34;&gt;&#xA;    &lt;div class=&#34;pagination-container&#34;&gt;&#xA;      &lt;!-- 分页控件将通过JavaScript动态生成 --&gt;&#xA;    &lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;style&gt;&#xA;.helmchart-user-index {&#xA;  padding: 10px;&#xA;}&#xA;&#xA;.charts-container {&#xA;  min-height: 400px;&#xA;  /* 在显示数据时，顶部的导航高度 */&#xA;  margin-top: 80px;&#xA;}&#xA;&#xA;.no-data {&#xA;  padding: 40px 0;&#xA;  text-align: center;&#xA;}&#xA;&#xA;.chart-grid {&#xA;  display: grid;&#xA;  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));&#xA;  gap: 20px;&#xA;  margin-bottom: 30px;&#xA;}&#xA;&#xA;.chart-item {&#xA;  cursor: pointer;&#xA;  transition: all 0.3s ease;&#xA;  border: 1.5px solid #ebeef5;&#xA;  display: flex;&#xA;  flex-direction: column;&#xA;  background: #fff;&#xA;  border-radius: 4px;&#xA;  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);&#xA;}&#xA;&#xA;.chart-item:hover {&#xA;  transform: translateY(-4px);&#xA;  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);&#xA;}&#xA;&#xA;.chart-content {&#xA;  padding: 20px;&#xA;  display: flex;&#xA;  flex-direction: column;&#xA;  flex: 1;&#xA;}&#xA;&#xA;.chart-main {&#xA;  flex: 1;&#xA;}&#xA;&#xA;.chart-header {&#xA;  display: flex;&#xA;  align-items: flex-start;&#xA;  margin-bottom: 15px;&#xA;  justify-content: space-between;&#xA;}&#xA;&#xA;.header-tag {&#xA;  flex-shrink: 0;&#xA;  margin-left: 10px;&#xA;  margin-top: 5px;&#xA;}&#xA;&#xA;.chart-info {&#xA;  flex: 1;&#xA;  min-width: 0;&#xA;}&#xA;&#xA;.chart-name {&#xA;  margin: 0 0 5px 0;&#xA;  font-size: 18px;&#xA;  font-weight: 600;&#xA;  color: #303133;&#xA;  white-space: nowrap;&#xA;  overflow: hidden;&#xA;  text-overflow: ellipsis;&#xA;}&#xA;&#xA;.chart-repourl {&#xA;  font-size: 12px;&#xA;  color: gray;&#xA;  margin: 0;&#xA;  overflow: hidden;&#xA;  text-overflow: ellipsis;&#xA;}&#xA;&#xA;.chart-description {&#xA;  margin-bottom: 15px;&#xA;  font-size: 14px;&#xA;  color: #606266;&#xA;  line-height: 1.5;&#xA;  display: -webkit-box;&#xA;  -webkit-box-orient: vertical;&#xA;  overflow: hidden;&#xA;  text-align: justify;&#xA;  word-wrap: break-word;&#xA;  word-break: break-word;&#xA;}&#xA;&#xA;.description-text {&#xA;  margin: 0;&#xA;  display: -webkit-box;&#xA;  -webkit-box-orient: vertical;&#xA;  -webkit-line-clamp: 4;&#xA;  overflow: hidden;&#xA;  text-overflow: ellipsis;&#xA;}&#xA;&#xA;.chart-meta {&#xA;  display: flex;&#xA;  justify-content: space-between;&#xA;  align-items: center;&#xA;  border-top: 1px solid #eee;&#xA;  padding-top: 15px;&#xA;  margin-top: auto;&#xA;}&#xA;&#xA;.chart-sync-period {&#xA;  font-size: 12px;&#xA;  color: #909399;&#xA;}&#xA;&#xA;.pagination-wrapper {&#xA;  display: flex;&#xA;  justify-content: flex-end;&#xA;  padding: 20px 0;&#xA;}&#xA;&#xA;.pagination-container {&#xA;  display: flex;&#xA;  align-items: center;&#xA;  gap: 10px;&#xA;}&#xA;&#xA;.pagination-info {&#xA;  font-size: 14px;&#xA;  color: #606266;&#xA;}&#xA;&#xA;.pagination-controls {&#xA;  display: flex;&#xA;  gap: 5px;&#xA;}&#xA;&#xA;.pagination-btn {&#xA;  padding: 5px 10px;&#xA;  border: 1px solid #dcdfe6;&#xA;  background: #fff;&#xA;  border-radius: 4px;&#xA;  cursor: pointer;&#xA;  font-size: 14px;&#xA;}&#xA;&#xA;.pagination-btn:hover {&#xA;  background: #ecf5ff;&#xA;  color: #409eff;&#xA;}&#xA;&#xA;.pagination-btn.disabled {&#xA;  color: #c0c4cc;&#xA;  cursor: not-allowed;&#xA;  background: #fff;&#xA;}&#xA;&#xA;.pagination-btn.disabled:hover {&#xA;  background: #fff;&#xA;}&#xA;&#xA;.pagination-btn.active {&#xA;  background: #409eff;&#xA;  color: #fff;&#xA;  border-color: #409eff;&#xA;}&#xA;&#xA;.page-sizes {&#xA;  margin-right: 10px;&#xA;}&#xA;&#xA;.page-sizes select {&#xA;  padding: 5px;&#xA;  border: 1px solid #dcdfe6;&#xA;  border-radius: 4px;&#xA;}&#xA;&#xA;.loading, .error {&#xA;  text-align: center;&#xA;  padding: 40px 0;&#xA;  font-size: 16px;&#xA;}&#xA;&#xA;.error {&#xA;  color: #f56565;&#xA;}&#xA;&#xA;.el-tag {&#xA;  background-color: #ecf5ff;&#xA;  border-color: #d9ecff;&#xA;  color: #409eff;&#xA;  padding: 0 10px;&#xA;  height: 24px;&#xA;  line-height: 22px;&#xA;  font-size: 12px;&#xA;  border-width: 1px;&#xA;  border-style: solid;&#xA;  border-radius: 4px;&#xA;  box-sizing: border-box;&#xA;  white-space: nowrap;&#xA;}&#xA;&#xA;@media (max-width: 768px) {&#xA;  .chart-grid {&#xA;    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));&#xA;    gap: 15px;&#xA;  }&#xA;}&#xA;&#xA;@media (max-width: 480px) {&#xA;  .chart-grid {&#xA;    grid-template-columns: 1fr;&#xA;  }&#xA;  &#xA;  .chart-header {&#xA;    flex-direction: column;&#xA;    align-items: center;&#xA;    text-align: center;&#xA;  }&#xA;  &#xA;  .header-tag {&#xA;    margin-top: 10px;&#xA;  }&#xA;}&#xA;&lt;/style&gt;&#xA;&lt;script&gt;&#xA;document.addEventListener(&#39;DOMContentLoaded&#39;, function() {&#xA;  // API端点URL&#xA;  const API_HELMCHART_URL = &#39;https://server.cs.cncfstack.com/api/v1/resources/helmchart/repo&#39;;&#xA;  &#xA;  // 数据状态&#xA;  let loading = false;&#xA;  let charts = [];&#xA;  &#xA;  // 分页相关&#xA;  let currentPage = 1;&#xA;  let pageSize = 50;&#xA;  let totalCharts = 0;&#xA;  &#xA;  // 搜索关键词&#xA;  let searchKeyword = &#39;12factor&#39;;&#xA;  &#xA;  // 格式化日期&#xA;  function formatDate(dateString) {&#xA;    const date = new Date(dateString);&#xA;    return date.toLocaleDateString(&#39;zh-CN&#39;);&#xA;  }&#xA;  &#xA;  // 提取主机名&#xA;  function getOriginalHostname(url) {&#xA;    const match = url.match(/^https?:\/\/([^\/]+)/i);&#xA;    return match ? match[1] : &#39;&#39;;&#xA;  }&#xA;  &#xA;  // 跳转到详情页&#xA;  function goToDetail(repo_url, chart_name) {&#xA;    const repo_host = getOriginalHostname(repo_url);&#xA;    window.open(`https://cncfstack.com/c/${repo_host}/${chart_name}`, &#39;_blank&#39;);&#xA;  }&#xA;  &#xA;  // 渲染图表网格&#xA;  function renderChartGrid(chartsData) {&#xA;    const container = document.querySelector(&#39;.charts-container&#39;);&#xA;    &#xA;    if (!chartsData || chartsData.length === 0) {&#xA;      container.innerHTML = `&#xA;        &lt;div class=&#34;no-data&#34;&gt;&#xA;          &lt;p&gt;暂无 HelmChart 数据&lt;/p&gt;</description>
    </item>
    <item>
      <title>镜像仓库</title>
      <link>https://cncfstack.com/p/12factor/image/</link>
      <pubDate>Fri, 20 Oct 2023 10:00:00 +0800</pubDate>
      <guid>https://cncfstack.com/p/12factor/image/</guid>
      <description>&lt;div id=&#34;image-grid-container&#34;&gt;&lt;/div&gt;&#xA;&lt;script&gt;&#xA;document.addEventListener(&#39;DOMContentLoaded&#39;, function() {&#xA;  // API端点URL（需要根据实际情况调整）&#xA;  const API_IMAGE_REPO_URL = &#39;https://server.cs.cncfstack.com/api/v1/image/repo&#39;; // 需要替换为实际的API地址&#xA;  &#xA;  // 格式化日期&#xA;  function formatDate(dateString) {&#xA;    const date = new Date(dateString);&#xA;    return date.toLocaleDateString(&#39;zh-CN&#39;);&#xA;  }&#xA;&#xA;  // 渲染镜像卡片&#xA;  function renderImageGrid(reposData) {&#xA;    const container = document.getElementById(&#39;image-grid-container&#39;);&#xA;    &#xA;    if (!container) {&#xA;      console.error(&#39;未找到ID为image-grid-container的元素&#39;);&#xA;      return;&#xA;    }&#xA;&#xA;    if (!reposData || reposData.length === 0) {&#xA;      container.innerHTML = `&#xA;        &lt;div class=&#34;no-images&#34;&gt;&#xA;          &lt;p&gt;暂无镜像数据&lt;/p&gt;&#xA;        &lt;/div&gt;&#xA;      `;&#xA;      return;&#xA;    }&#xA;&#xA;    let gridHTML = &#39;&lt;div class=&#34;image-grid&#34;&gt;&#39;;&#xA;    &#xA;    reposData.forEach(repo =&gt; {&#xA;      gridHTML += `&#xA;        &lt;div class=&#34;image-card&#34; onclick=&#34;viewRepoDetail(&#39;${repo.host_vendor}&#39;, &#39;${repo.image_repo}&#39;)&#34;&gt;&#xA;          &lt;div class=&#34;app-card-content&#34;&gt;&#xA;            &lt;div class=&#34;app-card-header&#34;&gt;&#xA;              &lt;div class=&#34;app-card-info&#34;&gt;&#xA;                &lt;h2 class=&#34;app-card-name&#34;&gt;${repo.image_repo}&lt;/h2&gt;&#xA;                &lt;p class=&#34;image-repo&#34;&gt;${repo.host_vendor}&lt;/p&gt;&#xA;              &lt;/div&gt;&#xA;              &lt;div class=&#34;header-tag&#34;&gt;&#xA;                &lt;span class=&#34;image-repo-tag&#34;&gt;镜像&lt;/span&gt;&#xA;              &lt;/div&gt;&#xA;            &lt;/div&gt;&#xA;            &#xA;            &lt;div class=&#34;app-card-description&#34;&gt;&#xA;              &lt;p class=&#34;app-card-description-text&#34;&gt;${repo.description || &#39;暂无描述&#39;}&lt;/p&gt;&#xA;            &lt;/div&gt;&#xA;            &#xA;            &lt;div class=&#34;app-card-image-meta&#34;&gt;&#xA;              &lt;span class=&#34;app-card-meta&#34;&gt;上次同步 ${formatDate(repo.sync_at)}&lt;/span&gt;&#xA;            &lt;/div&gt;&#xA;          &lt;/div&gt;&#xA;        &lt;/div&gt;&#xA;      `;&#xA;    });&#xA;    &#xA;    gridHTML += &#39;&lt;/div&gt;&#39;;&#xA;    container.innerHTML = gridHTML;&#xA;  }&#xA;&#xA;  // 查看仓库详情&#xA;  window.viewRepoDetail = function(hostVendor, imageRepo) {&#xA;    const name = `${hostVendor}/${imageRepo}`;&#xA;    window.open(`https://cncfstack.com/i/${name}`, &#39;_blank&#39;);&#xA;  };&#xA;&#xA;  // 从API加载数据&#xA;  async function loadData() {&#xA;    try {&#xA;      // 显示加载状态&#xA;      const container = document.getElementById(&#39;image-grid-container&#39;);&#xA;      container.innerHTML = &#39;&lt;div class=&#34;loading&#34;&gt;加载中...&lt;/div&gt;&#39;;&#xA;      &#xA;      // 发起API请求&#xA;      const response = await fetch(`${API_IMAGE_REPO_URL}?page=1&amp;page_size=50&amp;ready_check=true&amp;search_colume=all&amp;search_keyword=12factor`);&#xA;      &#xA;      if (!response.ok) {&#xA;        throw new Error(`HTTP error! status: ${response.status}`);&#xA;      }&#xA;      &#xA;      const result = await response.json();&#xA;      &#xA;      // 正确解析API响应数据&#xA;      let repos = [];&#xA;      if (result &amp;&amp; result.data) {&#xA;        // 如果data是一个数组，直接使用&#xA;        if (Array.isArray(result.data)) {&#xA;          repos = result.data;&#xA;        } &#xA;        // 如果data包含data字段且是数组，使用该字段&#xA;        else if (result.data.data &amp;&amp; Array.isArray(result.data.data)) {&#xA;          repos = result.data.data;&#xA;        }&#xA;      }&#xA;      &#xA;      // 渲染数据&#xA;      renderImageGrid(repos);&#xA;    } catch (error) {&#xA;      console.error(&#39;获取仓库列表失败:&#39;, error);&#xA;      const container = document.getElementById(&#39;image-grid-container&#39;);&#xA;      container.innerHTML = &#39;&lt;div class=&#34;error&#34;&gt;获取数据失败，请稍后重试&lt;/div&gt;&#39;;&#xA;    }&#xA;  }&#xA;&#xA;  // 初始化渲染&#xA;  loadData();&#xA;});&#xA;&lt;/script&gt;&#xA;&lt;style&gt;&#xA;/* image-grid.css */&#xA;.image-grid {&#xA;  display: grid;&#xA;  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));&#xA;  gap: 20px;&#xA;  margin-bottom: 30px;&#xA;  margin-top: 80px;&#xA;  padding: 20px;&#xA;}&#xA;&#xA;/* .image-card {&#xA;  cursor: pointer;&#xA;  transition: all 0.3s ease;&#xA;  border-radius: 4px;&#xA;  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);&#xA;  background: #fff;&#xA;} */&#xA;&#xA;.image-card {&#xA;  cursor: pointer;&#xA;  transition: all 0.3s ease;&#xA;  border-radius: 4px;&#xA;  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);&#xA;  background: #fff;&#xA;  /* 添加最大宽度限制 */&#xA;  max-width: 100%;&#xA;  width: 100%;&#xA;}&#xA;&#xA;.image-card:hover {&#xA;  transform: translateY(-4px);&#xA;  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);&#xA;}&#xA;&#xA;.app-card-content {&#xA;  padding: 20px;&#xA;  display: flex;&#xA;  flex-direction: column;&#xA;  flex: 1;&#xA;}&#xA;&#xA;.app-card-header {&#xA;  display: flex;&#xA;  align-items: flex-start;&#xA;  margin-bottom: 15px;&#xA;  justify-content: space-between;&#xA;}&#xA;&#xA;.header-tag {&#xA;  flex-shrink: 0;&#xA;  margin-left: 10px;&#xA;  margin-top: 5px;&#xA;}&#xA;&#xA;.app-card-info {&#xA;  flex: 1;&#xA;  min-width: 0;&#xA;}&#xA;&#xA;/* .app-card-name {&#xA;  margin: 0 0 5px 0;&#xA;  font-size: 18px;&#xA;  font-weight: 600;&#xA;  color: #303133;&#xA;  white-space: nowrap;&#xA;  overflow: hidden;&#xA;  text-overflow: ellipsis;&#xA;} */&#xA;&#xA;.app-card-name {&#xA;  margin: 0 0 5px 0;&#xA;  font-size: 18px;&#xA;  font-weight: 600;&#xA;  color: #303133;&#xA;  /* 修改以下属性以支持长文本换行 */&#xA;  white-space: normal;&#xA;  overflow: hidden;&#xA;  text-overflow: ellipsis;&#xA;  word-wrap: break-word;&#xA;  word-break: break-word;&#xA;  display: -webkit-box;&#xA;  -webkit-line-clamp: 2; /* 限制显示2行 */&#xA;  -webkit-box-orient: vertical;&#xA;}&#xA;&#xA;.image-repo {&#xA;  margin: 0;&#xA;  font-size: 13px;&#xA;  color: #606266;&#xA;  overflow: hidden;&#xA;  text-overflow: ellipsis;&#xA;}&#xA;&#xA;.app-card-description {&#xA;  margin-bottom: 15px;&#xA;  font-size: 14px;&#xA;  color: #606266;&#xA;  line-height: 1.5;&#xA;  display: -webkit-box;&#xA;  -webkit-box-orient: vertical;&#xA;  overflow: hidden;&#xA;  text-align: justify;&#xA;  min-height: 60px;&#xA;  word-wrap: break-word;&#xA;  word-break: break-word;&#xA;}&#xA;&#xA;.app-card-description-text {&#xA;  margin: 0;&#xA;  display: -webkit-box;&#xA;  -webkit-box-orient: vertical;&#xA;  overflow: hidden;&#xA;  text-overflow: ellipsis;&#xA;}&#xA;&#xA;.app-card-image-meta {&#xA;  display: flex;&#xA;  justify-content: space-between;&#xA;  align-items: center;&#xA;  border-top: 1px solid #eee;&#xA;  padding-top: 15px;&#xA;  margin-top: auto;&#xA;}&#xA;&#xA;.app-card-meta {&#xA;  font-size: 12px;&#xA;  color: #909399;&#xA;}&#xA;&#xA;.no-images {&#xA;  grid-column: 1 / -1;&#xA;  text-align: center;&#xA;  padding: 50px 0;&#xA;}&#xA;&#xA;.loading, .error {&#xA;  grid-column: 1 / -1;&#xA;  text-align: center;&#xA;  padding: 50px 0;&#xA;  font-size: 16px;&#xA;}&#xA;&#xA;.error {&#xA;  color: #f56565;&#xA;}&#xA;&#xA;.image-repo-tag {&#xA;  background-color: #ecf5ff;&#xA;  border-color: #d9ecff;&#xA;  color: #409eff;&#xA;  padding: 0 10px;&#xA;  height: 24px;&#xA;  line-height: 22px;&#xA;  font-size: 12px;&#xA;  border-width: 1px;&#xA;  border-style: solid;&#xA;  border-radius: 4px;&#xA;  box-sizing: border-box;&#xA;  white-space: nowrap;&#xA;}&#xA;&#xA;@media (max-width: 768px) {&#xA;  .image-grid {&#xA;    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));&#xA;    gap: 15px;&#xA;  }&#xA;}&#xA;/* &#xA;@media (max-width: 480px) {&#xA;  .image-grid {&#xA;    grid-template-columns: 1fr;&#xA;  }&#xA;  &#xA;  .app-card-header {&#xA;    flex-direction: column;&#xA;    align-items: center;&#xA;    text-align: center;&#xA;  }&#xA;} */&#xA;&#xA;@media (max-width: 480px) {&#xA;  .image-grid {&#xA;    grid-template-columns: 1fr;&#xA;    padding: 10px;&#xA;  }&#xA;  &#xA;  .app-card-header {&#xA;    flex-direction: column;&#xA;    align-items: center;&#xA;    text-align: center;&#xA;  }&#xA;  &#xA;  .app-card-content {&#xA;    padding: 15px;&#xA;  }&#xA;  &#xA;  .app-card-name {&#xA;    font-size: 16px;&#xA;    -webkit-line-clamp: 3; /* 移动端允许显示更多行 */&#xA;  }&#xA;}&#xA;&lt;/style&gt;</description>
    </item>
    <item>
      <title>I. 基准代码</title>
      <link>https://cncfstack.com/p/12factor/docs/codebase/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/codebase/</guid>
      <description>&lt;h2 id=&#34;一份基准代码codebase多份部署deploy&#34;&gt;一份基准代码（&lt;em&gt;Codebase&lt;/em&gt;），多份部署（&lt;em&gt;deploy&lt;/em&gt;）&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e4%b8%80%e4%bb%bd%e5%9f%ba%e5%87%86%e4%bb%a3%e7%a0%81codebase%e5%a4%9a%e4%bb%bd%e9%83%a8%e7%bd%b2deploy&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;12-Factor应用(译者注：应该是说一个使用本文概念来设计的应用，下同)通常会使用版本控制系统加以管理，如&lt;a href=&#34;http://git-scm.com/&#34;&gt;Git&lt;/a&gt;, &lt;a href=&#34;https://www.mercurial-scm.org/&#34;&gt;Mercurial&lt;/a&gt;, &lt;a href=&#34;http://subversion.apache.org/&#34;&gt;Subversion&lt;/a&gt;。一份用来跟踪代码所有修订版本的数据库被称作 &lt;em&gt;代码库&lt;/em&gt;（code repository, code repo, repo）。&lt;/p&gt;&#xA;&lt;p&gt;在类似 SVN 这样的集中式版本控制系统中，&lt;em&gt;基准代码&lt;/em&gt; 就是指控制系统中的这一份代码库；而在 Git 那样的分布式版本控制系统中，&lt;em&gt;基准代码&lt;/em&gt; 则是指最上游的那份代码库。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;images/codebase-deploys.png&#34; alt=&#34;一份代码库对应多份部署&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;基准代码和应用之间总是保持一一对应的关系：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一旦有多个基准代码，就不能称为一个应用，而是一个分布式系统。分布式系统中的每一个组件都是一个应用，每一个应用可以分别使用 12-Factor 进行开发。&lt;/li&gt;&#xA;&lt;li&gt;多个应用共享一份基准代码是有悖于 12-Factor 原则的。解决方案是将共享的代码拆分为独立的类库，然后使用 &lt;a href=&#34;./dependencies&#34;&gt;依赖管理&lt;/a&gt; 策略去加载它们。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;尽管每个应用只对应一份基准代码，但可以同时存在多份部署。每份 &lt;em&gt;部署&lt;/em&gt; 相当于运行了一个应用的实例。通常会有一个生产环境，一个或多个预发布环境。此外，每个开发人员都会在自己本地环境运行一个应用实例，这些都相当于一份部署。&lt;/p&gt;&#xA;&lt;p&gt;所有部署的基准代码相同，但每份部署可以使用其不同的版本。比如，开发人员可能有一些提交还没有同步至预发布环境；预发布环境也有一些提交没有同步至生产环境。但它们都共享一份基准代码，我们就认为它们只是相同应用的不同部署而已。&lt;/p&gt;</description>
    </item>
    <item>
      <title>II. 依赖</title>
      <link>https://cncfstack.com/p/12factor/docs/dependencies/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/dependencies/</guid>
      <description>&lt;h2 id=&#34;显式声明依赖关系-dependency-&#34;&gt;显式声明依赖关系（ &lt;em&gt;dependency&lt;/em&gt; ）&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e6%98%be%e5%bc%8f%e5%a3%b0%e6%98%8e%e4%be%9d%e8%b5%96%e5%85%b3%e7%b3%bb-dependency-&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;大多数编程语言都会提供一个打包系统，用来为各个类库提供打包服务，就像 Perl 的 &lt;a href=&#34;http://www.cpan.org/&#34;&gt;CPAN&lt;/a&gt; 或是 Ruby 的 &lt;a href=&#34;http://rubygems.org/&#34;&gt;Rubygems&lt;/a&gt; 。通过打包系统安装的类库可以是系统级的（称之为 &amp;ldquo;site packages&amp;rdquo;），或仅供某个应用程序使用，部署在相应的目录中（称之为 &amp;ldquo;vendoring&amp;rdquo; 或 &amp;ldquo;bunding&amp;rdquo;）。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;12-Factor规则下的应用程序不会隐式依赖系统级的类库。&lt;/strong&gt; 它一定通过 &lt;em&gt;依赖清单&lt;/em&gt; ，确切地声明所有依赖项。此外，在运行过程中通过 &lt;em&gt;依赖隔离&lt;/em&gt; 工具来确保程序不会调用系统中存在但清单中未声明的依赖项。这一做法会统一应用到生产和开发环境。&lt;/p&gt;&#xA;&lt;p&gt;例如， Ruby 的 &lt;a href=&#34;https://bundler.io/&#34;&gt;Bundler&lt;/a&gt; 使用 &lt;code&gt;Gemfile&lt;/code&gt; 作为依赖项声明清单，使用 &lt;code&gt;bundle exec&lt;/code&gt; 来进行依赖隔离。Python 中则可分别使用两种工具 &amp;ndash; &lt;a href=&#34;http://www.pip-installer.org/en/latest/&#34;&gt;Pip&lt;/a&gt; 用作依赖声明， &lt;a href=&#34;http://www.virtualenv.org/en/latest/&#34;&gt;Virtualenv&lt;/a&gt; 用作依赖隔离。甚至 C 语言也有类似工具， &lt;a href=&#34;http://www.gnu.org/s/autoconf/&#34;&gt;Autoconf&lt;/a&gt; 用作依赖声明，静态链接库用作依赖隔离。无论用什么工具，依赖声明和依赖隔离必须一起使用，否则无法满足 12-Factor 规范。&lt;/p&gt;&#xA;&lt;p&gt;显式声明依赖的优点之一是为新进开发者简化了环境配置流程。新进开发者可以检出应用程序的基准代码，安装编程语言环境和它对应的依赖管理工具，只需通过一个 &lt;em&gt;构建命令&lt;/em&gt; 来安装所有的依赖项，即可开始工作。例如，Ruby/Bundler 下使用 &lt;code&gt;bundle install&lt;/code&gt;，而 Clojure/&lt;a href=&#34;https://github.com/technomancy/leiningen#readme&#34;&gt;Leiningen&lt;/a&gt; 则是 &lt;code&gt;lein deps&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;12-Factor 应用同样不会隐式依赖某些系统工具，如 ImageMagick 或是&lt;code&gt;curl&lt;/code&gt;。即使这些工具存在于几乎所有系统，但终究无法保证所有未来的系统都能支持应用顺利运行，或是能够和应用兼容。如果应用必须使用到某些系统工具，那么这些工具应该被包含在应用之中。&lt;/p&gt;</description>
    </item>
    <item>
      <title>III. 配置</title>
      <link>https://cncfstack.com/p/12factor/docs/config/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/config/</guid>
      <description>&lt;h2 id=&#34;在环境中存储配置&#34;&gt;在环境中存储配置&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e5%9c%a8%e7%8e%af%e5%a2%83%e4%b8%ad%e5%ad%98%e5%82%a8%e9%85%8d%e7%bd%ae&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;通常，应用的 &lt;em&gt;配置&lt;/em&gt; 在不同 &lt;a href=&#34;./codebase&#34;&gt;部署&lt;/a&gt; (预发布、生产环境、开发环境等等)间会有很大差异。这其中包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;数据库，Memcached，以及其他 &lt;a href=&#34;./backing-services&#34;&gt;后端服务&lt;/a&gt; 的配置&lt;/li&gt;&#xA;&lt;li&gt;第三方服务的证书，如 Amazon S3、Twitter 等&lt;/li&gt;&#xA;&lt;li&gt;每份部署特有的配置，如域名等&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;有些应用在代码中使用常量保存配置，这与 12-Factor 所要求的&lt;strong&gt;代码和配置严格分离&lt;/strong&gt;显然大相径庭。配置文件在各部署间存在大幅差异，代码却完全一致。&lt;/p&gt;&#xA;&lt;p&gt;判断一个应用是否正确地将配置排除在代码之外，一个简单的方法是看该应用的基准代码是否可以立刻开源，而不用担心会暴露任何敏感的信息。&lt;/p&gt;&#xA;&lt;p&gt;需要指出的是，这里定义的&amp;quot;配置&amp;quot;并&lt;strong&gt;不&lt;/strong&gt;包括应用的内部配置，比如 Rails 的 &lt;code&gt;config/routes.rb&lt;/code&gt;，或是使用 &lt;a href=&#34;http://spring.io/&#34;&gt;Spring&lt;/a&gt; 时 &lt;a href=&#34;http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html&#34;&gt;代码模块间的依赖注入关系&lt;/a&gt; 。这类配置在不同部署间不存在差异，所以应该写入代码。&lt;/p&gt;&#xA;&lt;p&gt;另外一个解决方法是使用配置文件，但不把它们纳入版本控制系统，就像 Rails 的 &lt;code&gt;config/database.yml&lt;/code&gt; 。这相对于在代码中使用常量已经是长足进步，但仍然有缺点：总是会不小心将配置文件签入了代码库；配置文件的可能会分散在不同的目录，并有着不同的格式，这让找出一个地方来统一管理所有配置变的不太现实。更糟的是，这些格式通常是语言或框架特定的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;12-Factor推荐将应用的配置存储于 &lt;em&gt;环境变量&lt;/em&gt; 中&lt;/strong&gt;（ &lt;em&gt;env vars&lt;/em&gt;, &lt;em&gt;env&lt;/em&gt; ）。环境变量可以非常方便地在不同的部署间做修改，却不动一行代码；与配置文件不同，不小心把它们签入代码库的概率微乎其微；与一些传统的解决配置问题的机制（比如 Java 的属性配置文件）相比，环境变量与语言和系统无关。&lt;/p&gt;&#xA;&lt;p&gt;配置管理的另一个方面是分组。有时应用会将配置按照特定部署进行分组（或叫做“环境”），例如Rails中的 &lt;code&gt;development&lt;/code&gt;,&lt;code&gt;test&lt;/code&gt;, 和 &lt;code&gt;production&lt;/code&gt; 环境。这种方法无法轻易扩展：更多部署意味着更多新的环境，例如 &lt;code&gt;staging&lt;/code&gt; 或 &lt;code&gt;qa&lt;/code&gt; 。 随着项目的不断深入，开发人员可能还会添加他们自己的环境，比如 &lt;code&gt;joes-staging&lt;/code&gt; ，这将导致各种配置组合的激增，从而给管理部署增加了很多不确定因素。&lt;/p&gt;&#xA;&lt;p&gt;12-Factor 应用中，环境变量的粒度要足够小，且相对独立。它们永远也不会组合成一个所谓的“环境”，而是独立存在于每个部署之中。当应用程序不断扩展，需要更多种类的部署时，这种配置管理方式能够做到平滑过渡。&lt;/p&gt;</description>
    </item>
    <item>
      <title>IV. 后端服务</title>
      <link>https://cncfstack.com/p/12factor/docs/backing-services/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/backing-services/</guid>
      <description>&lt;h2 id=&#34;把后端服务backing-services当作附加资源&#34;&gt;把后端服务(&lt;em&gt;backing services&lt;/em&gt;)当作附加资源&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e6%8a%8a%e5%90%8e%e7%ab%af%e6%9c%8d%e5%8a%a1backing-services%e5%bd%93%e4%bd%9c%e9%99%84%e5%8a%a0%e8%b5%84%e6%ba%90&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;em&gt;后端服务&lt;/em&gt;是指程序运行所需要的通过网络调用的各种服务，如数据库（&lt;a href=&#34;http://dev.mysql.com/&#34;&gt;MySQL&lt;/a&gt;，&lt;a href=&#34;http://couchdb.apache.org/&#34;&gt;CouchDB&lt;/a&gt;），消息/队列系统（&lt;a href=&#34;http://www.rabbitmq.com/&#34;&gt;RabbitMQ&lt;/a&gt;，&lt;a href=&#34;https://beanstalkd.github.io&#34;&gt;Beanstalkd&lt;/a&gt;），SMTP 邮件发送服务（&lt;a href=&#34;http://www.postfix.org/&#34;&gt; Postfix&lt;/a&gt;），以及缓存系统（&lt;a href=&#34;http://memcached.org/&#34;&gt;Memcached&lt;/a&gt;）。&lt;/p&gt;&#xA;&lt;p&gt;类似数据库的后端服务，通常由部署应用程序的系统管理员一起管理。除了本地服务之外，应用程序有可能使用了第三方发布和管理的服务。示例包括 SMTP（例如 &lt;a href=&#34;http://postmarkapp.com/&#34;&gt;Postmark&lt;/a&gt;），数据收集服务（例如 &lt;a href=&#34;http://newrelic.com/&#34;&gt;New Relic&lt;/a&gt; 或 &lt;a href=&#34;http://www.loggly.com/&#34;&gt;Loggly&lt;/a&gt;），数据存储服务（如 &lt;a href=&#34;http://http://aws.amazon.com/s3/&#34;&gt;Amazon S3&lt;/a&gt;），以及使用 API 访问的服务（例如 &lt;a href=&#34;http://dev.twitter.com/&#34;&gt;Twitter&lt;/a&gt;, &lt;a href=&#34;https://developers.google.com/maps/&#34;&gt;Google Maps&lt;/a&gt;, &lt;a href=&#34;http://www.last.fm/api&#34;&gt;Last.fm&lt;/a&gt;）。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;12-Factor 应用不会区别对待本地或第三方服务。&lt;/strong&gt; 对应用程序而言，两种都是附加资源，通过一个 url 或是其他存储在 &lt;a href=&#34;./config&#34;&gt;配置&lt;/a&gt; 中的服务定位/服务证书来获取数据。12-Factor 应用的任意 &lt;a href=&#34;./codebase&#34;&gt;部署&lt;/a&gt; ，都应该可以在不进行任何代码改动的情况下，将本地 MySQL 数据库换成第三方服务（例如 &lt;a href=&#34;http://aws.amazon.com/rds/&#34;&gt;Amazon RDS&lt;/a&gt;）。类似的，本地 SMTP 服务应该也可以和第三方 SMTP 服务（例如 Postmark ）互换。上述 2 个例子中，仅需修改配置中的资源地址。&lt;/p&gt;&#xA;&lt;p&gt;每个不同的后端服务是一份 &lt;em&gt;资源&lt;/em&gt; 。例如，一个 MySQL 数据库是一个资源，两个 MySQL 数据库（用来数据分区）就被当作是 2 个不同的资源。12-Factor 应用将这些数据库都视作 &lt;em&gt;附加资源&lt;/em&gt; ，这些资源和它们附属的部署保持松耦合。&lt;/p&gt;&#xA;&lt;img src=&#34;images/attached-resources.png&#34; class=&#34;full&#34; alt=&#34;一种部署附加4个后端服务&#34; /&gt;&#xA;&lt;p&gt;部署可以按需加载或卸载资源。例如，如果应用的数据库服务由于硬件问题出现异常，管理员可以从最近的备份中恢复一个数据库，卸载当前的数据库，然后加载新的数据库 &amp;ndash; 整个过程都不需要修改代码。&lt;/p&gt;</description>
    </item>
    <item>
      <title>IX. 易处理</title>
      <link>https://cncfstack.com/p/12factor/docs/disposability/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/disposability/</guid>
      <description>&lt;h2 id=&#34;快速启动和优雅终止可最大化健壮性&#34;&gt;快速启动和优雅终止可最大化健壮性&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e5%bf%ab%e9%80%9f%e5%90%af%e5%8a%a8%e5%92%8c%e4%bc%98%e9%9b%85%e7%bb%88%e6%ad%a2%e5%8f%af%e6%9c%80%e5%a4%a7%e5%8c%96%e5%81%a5%e5%a3%ae%e6%80%a7&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;**12-Factor 应用的 &lt;a href=&#34;./processes&#34;&gt;进程&lt;/a&gt; 是 &lt;em&gt;易处理（disposable）&lt;em&gt;的，意思是说它们可以瞬间开启或停止。&lt;/em&gt;&lt;/em&gt; 这有利于快速、弹性的伸缩应用，迅速部署变化的 &lt;a href=&#34;./codebase&#34;&gt;代码&lt;/a&gt; 或 &lt;a href=&#34;./config&#34;&gt;配置&lt;/a&gt; ，稳健的部署应用。&lt;/p&gt;&#xA;&lt;p&gt;进程应当追求 &lt;strong&gt;最小启动时间&lt;/strong&gt; 。 理想状态下，进程从敲下命令到真正启动并等待请求的时间应该只需很短的时间。更少的启动时间提供了更敏捷的 &lt;a href=&#34;./build-release-run&#34;&gt;发布&lt;/a&gt; 以及扩展过程，此外还增加了健壮性，因为进程管理器可以在授权情形下容易的将进程搬到新的物理机器上。&lt;/p&gt;&#xA;&lt;p&gt;进程 &lt;strong&gt;一旦接收 &lt;a href=&#34;http://en.wikipedia.org/wiki/SIGTERM&#34;&gt;终止信号（&lt;code&gt;SIGTERM&lt;/code&gt;）&lt;/a&gt; 就会优雅的终止&lt;/strong&gt; 。就网络进程而言，优雅终止是指停止监听服务的端口，即拒绝所有新的请求，并继续执行当前已接收的请求，然后退出。此类型的进程所隐含的要求是HTTP请求大多都很短(不会超过几秒钟)，而在长时间轮询中，客户端在丢失连接后应该马上尝试重连。&lt;/p&gt;&#xA;&lt;p&gt;对于 worker 进程来说，优雅终止是指将当前任务退回队列。例如，&lt;a href=&#34;http://www.rabbitmq.com/&#34;&gt;RabbitMQ&lt;/a&gt; 中，worker 可以发送一个&lt;a href=&#34;http://www.rabbitmq.com/amqp-0-9-1-quickref.html#basic.nack&#34;&gt;&lt;code&gt;NACK&lt;/code&gt;&lt;/a&gt;信号。 &lt;a href=&#34;https://beanstalkd.github.io&#34;&gt;Beanstalkd&lt;/a&gt; 中，任务终止并退回队列会在worker断开时自动触发。有锁机制的系统诸如 &lt;a href=&#34;https://github.com/collectiveidea/delayed_job#readme&#34;&gt;Delayed Job&lt;/a&gt; 则需要确定释放了系统资源。此类型的进程所隐含的要求是，任务都应该 &lt;a href=&#34;http://en.wikipedia.org/wiki/Reentrant_%28subroutine%29&#34;&gt;可重复执行&lt;/a&gt; ， 这主要由将结果包装进事务或是使重复操作 &lt;a href=&#34;http://en.wikipedia.org/wiki/Idempotence&#34;&gt;幂等&lt;/a&gt; 来实现。&lt;/p&gt;&#xA;&lt;p&gt;进程还应当&lt;strong&gt;在面对突然死亡时保持健壮&lt;/strong&gt;，例如底层硬件故障。虽然这种情况比起优雅终止来说少之又少，但终究有可能发生。一种推荐的方式是使用一个健壮的后端队列，例如 &lt;a href=&#34;https://beanstalkd.github.io&#34;&gt;Beanstalkd&lt;/a&gt; ，它可以在客户端断开或超时后自动退回任务。无论如何，12-Factor 应用都应该可以设计能够应对意外的、不优雅的终结。&lt;a href=&#34;http://lwn.net/Articles/191059/&#34;&gt;Crash-only design&lt;/a&gt; 将这种概念转化为 &lt;a href=&#34;http://couchdb.apache.org/docs/overview.html&#34;&gt;合乎逻辑的理论&lt;/a&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Logo</title>
      <link>https://cncfstack.com/p/12factor/logo/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/logo/</guid>
      <description>&lt;div id=&#34;dynamic-content&#34;&gt;&#xA;  &lt;p&gt;正在加载动态内容...&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;style&gt;&#xA;/* 保留原有样式 */&#xA;.image-list-container {&#xA;  max-width: 1200px;&#xA;  margin: 2rem auto;&#xA;  padding: 0 1rem;&#xA;}&#xA;&#xA;.image-list-title {&#xA;  text-align: center;&#xA;  margin-bottom: 2rem;&#xA;  color: #333;&#xA;  font-size: 1.8rem;&#xA;}&#xA;&#xA;.image-grid {&#xA;  display: grid;&#xA;  grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));&#xA;  gap: 1.5rem;&#xA;}&#xA;&#xA;.image-card {&#xA;  border: 1px solid #e1e8ed;&#xA;  border-radius: 8px;&#xA;  overflow: hidden;&#xA;  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);&#xA;  transition: transform 0.3s ease, box-shadow 0.3s ease;&#xA;  background: white;&#xA;  cursor: pointer;&#xA;}&#xA;&#xA;.image-card:hover {&#xA;  transform: translateY(-5px);&#xA;  box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);&#xA;}&#xA;&#xA;.card-link {&#xA;  text-decoration: none;&#xA;  color: inherit;&#xA;}&#xA;&#xA;.card-header {&#xA;  background-color: #f5f8fa;&#xA;  padding: 1rem;&#xA;  border-bottom: 1px solid #e1e8ed;&#xA;}&#xA;&#xA;.card-title {&#xA;  margin: 0;&#xA;  font-size: 1.2rem;&#xA;  color: #1da1f2;&#xA;  font-weight: 600;&#xA;}&#xA;&#xA;.card-body {&#xA;  padding: 1rem;&#xA;}&#xA;&#xA;.vendor-info {&#xA;  display: flex;&#xA;  align-items: center;&#xA;  margin-bottom: 0.8rem;&#xA;}&#xA;&#xA;.vendor-icon {&#xA;  width: 32px;&#xA;  height: 32px;&#xA;  background-color: #1da1f2;&#xA;  border-radius: 50%;&#xA;  display: flex;&#xA;  align-items: center;&#xA;  justify-content: center;&#xA;  color: white;&#xA;  font-weight: bold;&#xA;  margin-right: 0.8rem;&#xA;}&#xA;&#xA;.vendor-name {&#xA;  font-weight: 500;&#xA;  color: #333;&#xA;}&#xA;&#xA;.repo-info {&#xA;  background-color: #f8f9fa;&#xA;  padding: 0.8rem;&#xA;  border-radius: 4px;&#xA;  font-family: &#39;Courier New&#39;, monospace;&#xA;  font-size: 0.9rem;&#xA;  color: #333;&#xA;  word-break: break-all;&#xA;  margin-bottom: 0;&#xA;}&#xA;&#xA;.error-message {&#xA;  text-align: center;&#xA;  color: #e02d2d;&#xA;  padding: 2rem;&#xA;  font-size: 1.1rem;&#xA;}&#xA;&#xA;.loading-message {&#xA;  text-align: center;&#xA;  padding: 2rem;&#xA;  font-size: 1.1rem;&#xA;  color: #657786;&#xA;}&#xA;&#xA;@media (max-width: 768px) {&#xA;  .image-grid {&#xA;    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));&#xA;    gap: 1rem;&#xA;  }&#xA;  &#xA;  .image-list-title {&#xA;    font-size: 1.5rem;&#xA;  }&#xA;}&#xA;&#xA;/* 新增Logo展示样式 */&#xA;.logo-repo-container {&#xA;  padding: 20px;&#xA;  max-width: 1400px;&#xA;  margin: 80px auto;&#xA;}&#xA;&#xA;.logo-grid {&#xA;  display: grid;&#xA;  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));&#xA;  gap: 20px;&#xA;  margin-bottom: 20px;&#xA;}&#xA;&#xA;.logo-card {&#xA;  cursor: pointer;&#xA;  transition: all 0.3s ease;&#xA;  border-radius: 8px;&#xA;  overflow: hidden;&#xA;  background: white;&#xA;  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);&#xA;  position: relative;&#xA;}&#xA;&#xA;.logo-card:hover {&#xA;  transform: translateY(-5px);&#xA;  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);&#xA;}&#xA;&#xA;.logo-image-container {&#xA;  height: 160px;&#xA;  overflow: hidden;&#xA;  display: flex;&#xA;  align-items: center;&#xA;  justify-content: center;&#xA;  background-color: #f0f2f5;&#xA;  position: relative;&#xA;}&#xA;&#xA;.logo-image {&#xA;  max-width: 100%;&#xA;  max-height: 100%;&#xA;  object-fit: contain;&#xA;}&#xA;&#xA;.image-repo-tag {&#xA;  position: absolute;&#xA;  top: 8px;&#xA;  right: 8px;&#xA;  background-color: #ecf5ff;&#xA;  color: #409eff;&#xA;  padding: 3px 8px;&#xA;  border-radius: 4px;&#xA;  font-size: 12px;&#xA;}&#xA;&#xA;.image-error {&#xA;  display: flex;&#xA;  flex-direction: column;&#xA;  align-items: center;&#xA;  justify-content: center;&#xA;  height: 100%;&#xA;  color: #909399;&#xA;  font-size: 14px;&#xA;}&#xA;&#xA;.pagination-container {&#xA;  display: flex;&#xA;  justify-content: center;&#xA;  padding: 20px 0;&#xA;}&#xA;&#xA;.el-pagination {&#xA;  display: flex;&#xA;  align-items: center;&#xA;  gap: 10px;&#xA;  flex-wrap: wrap;&#xA;  justify-content: center;&#xA;}&#xA;&#xA;.pagination-info {&#xA;  font-size: 14px;&#xA;  color: #606266;&#xA;}&#xA;&#xA;.pagination-sizes {&#xA;  display: flex;&#xA;  align-items: center;&#xA;  gap: 5px;&#xA;}&#xA;&#xA;.page-size-select {&#xA;  padding: 5px;&#xA;  border: 1px solid #dcdfe6;&#xA;  border-radius: 4px;&#xA;}&#xA;&#xA;.pagination-controls {&#xA;  display: flex;&#xA;  align-items: center;&#xA;  gap: 5px;&#xA;}&#xA;&#xA;.pagination-btn {&#xA;  padding: 5px 10px;&#xA;  border: 1px solid #dcdfe6;&#xA;  background: white;&#xA;  border-radius: 4px;&#xA;  cursor: pointer;&#xA;}&#xA;&#xA;.pagination-btn.disabled {&#xA;  color: #c0c4cc;&#xA;  cursor: not-allowed;&#xA;}&#xA;&#xA;.pagination-btn.active {&#xA;  background-color: #409eff;&#xA;  color: white;&#xA;  border-color: #409eff;&#xA;}&#xA;&#xA;.pagination-jump {&#xA;  display: flex;&#xA;  align-items: center;&#xA;  gap: 5px;&#xA;  font-size: 14px;&#xA;  color: #606266;&#xA;}&#xA;&#xA;.pagination-input {&#xA;  width: 50px;&#xA;  padding: 5px;&#xA;  border: 1px solid #dcdfe6;&#xA;  border-radius: 4px;&#xA;}&#xA;&#xA;.pagination-go-btn {&#xA;  padding: 5px 10px;&#xA;  border: 1px solid #409eff;&#xA;  background: white;&#xA;  color: #409eff;&#xA;  border-radius: 4px;&#xA;  cursor: pointer;&#xA;}&#xA;&#xA;.drawer-overlay {&#xA;  position: fixed;&#xA;  top: 0;&#xA;  right: 0;&#xA;  bottom: 0;&#xA;  left: 0;&#xA;  background-color: rgba(0, 0, 0, 0.5);&#xA;  z-index: 1000;&#xA;  display: none;&#xA;}&#xA;&#xA;.drawer-overlay.visible {&#xA;  display: block;&#xA;}&#xA;&#xA;.detail-drawer {&#xA;  position: fixed;&#xA;  top: 0;&#xA;  right: 0;&#xA;  bottom: 0;&#xA;  width: 50%;&#xA;  background: white;&#xA;  z-index: 1001;&#xA;  transform: translateX(100%);&#xA;  transition: transform 0.3s ease;&#xA;  display: flex;&#xA;  flex-direction: column;&#xA;  overflow: hidden;&#xA;}&#xA;&#xA;.detail-drawer.open {&#xA;  transform: translateX(0);&#xA;}&#xA;&#xA;.drawer-header {&#xA;  padding: 15px 20px;&#xA;  border-bottom: 1px solid #eee;&#xA;  display: flex;&#xA;  justify-content: space-between;&#xA;  align-items: center;&#xA;}&#xA;&#xA;.drawer-title {&#xA;  font-size: 18px;&#xA;  font-weight: 600;&#xA;  margin: 0;&#xA;}&#xA;&#xA;.close-btn {&#xA;  background: none;&#xA;  border: none;&#xA;  font-size: 20px;&#xA;  cursor: pointer;&#xA;  color: #909399;&#xA;}&#xA;&#xA;.drawer-content {&#xA;  flex: 1;&#xA;  overflow-y: auto;&#xA;  padding: 20px;&#xA;  display: flex;&#xA;  flex-direction: column;&#xA;  gap: 20px;&#xA;}&#xA;&#xA;.detail-image-container {&#xA;  height: 370px;&#xA;  display: flex;&#xA;  align-items: center;&#xA;  justify-content: center;&#xA;  background-color: #f0f2f5;&#xA;  border-radius: 8px;&#xA;  overflow: hidden;&#xA;}&#xA;&#xA;.detail-image {&#xA;  max-width: 100%;&#xA;  max-height: 100%;&#xA;  object-fit: contain;&#xA;}&#xA;&#xA;.detail-info {&#xA;  flex: 1;&#xA;}&#xA;&#xA;.detail-actions {&#xA;  margin-top: 20px;&#xA;  text-align: center;&#xA;}&#xA;&#xA;.btn-download {&#xA;  background-color: #409eff;&#xA;  color: white;&#xA;  border: none;&#xA;  border-radius: 4px;&#xA;  padding: 12px 30px;&#xA;  font-size: 16px;&#xA;  cursor: pointer;&#xA;  display: inline-flex;&#xA;  align-items: center;&#xA;  gap: 5px;&#xA;}&#xA;&#xA;.btn-download:hover {&#xA;  background-color: #337ecc;&#xA;}&#xA;&#xA;.btn-download.loading {&#xA;  opacity: 0.8;&#xA;  cursor: not-allowed;&#xA;}&#xA;&#xA;.descriptions {&#xA;  border: 1px solid #ebeef5;&#xA;  border-radius: 4px;&#xA;  overflow: hidden;&#xA;}&#xA;&#xA;.desc-row {&#xA;  display: flex;&#xA;  border-bottom: 1px solid #ebeef5;&#xA;}&#xA;&#xA;.desc-row:last-child {&#xA;  border-bottom: none;&#xA;}&#xA;&#xA;.desc-label {&#xA;  width: 30%;&#xA;  padding: 12px 15px;&#xA;  background-color: #fafafa;&#xA;  color: #606266;&#xA;  font-size: 14px;&#xA;}&#xA;&#xA;.desc-content {&#xA;  flex: 1;&#xA;  padding: 12px 15px;&#xA;  color: #303133;&#xA;  font-size: 14px;&#xA;}&#xA;&#xA;.loading-indicator {&#xA;  text-align: center;&#xA;  padding: 20px;&#xA;  color: #606266;&#xA;}&#xA;&#xA;.error-message {&#xA;  text-align: center;&#xA;  padding: 20px;&#xA;  color: #f56c6c;&#xA;}&#xA;&#xA;.svg-container {&#xA;  width: 100%;&#xA;  height: 100%;&#xA;  display: flex;&#xA;  align-items: center;&#xA;  justify-content: center;&#xA;}&#xA;&#xA;.svg-image {&#xA;  width: 80%;&#xA;  height: 80%;&#xA;}&#xA;&#xA;@media (max-width: 768px) {&#xA;  .logo-grid {&#xA;    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));&#xA;    gap: 10px;&#xA;  }&#xA;  &#xA;  .detail-drawer {&#xA;    width: 100%;&#xA;  }&#xA;}&#xA;&lt;/style&gt;&#xA;&lt;script&gt;&#xA;// 全局变量&#xA;let tableData = [];&#xA;let currentPage = 1;&#xA;let pageSize = 48;&#xA;let totalTasks = 0;&#xA;let searchKeyword = &#39;12factor&#39;;&#xA;let currentFileData = null;&#xA;let totalLogo = 0;&#xA;let downloadLoadingStatus = false;&#xA;&#xA;// DOM元素引用&#xA;const dynamicContent = document.getElementById(&#39;dynamic-content&#39;);&#xA;&#xA;// 初始化&#xA;document.addEventListener(&#39;DOMContentLoaded&#39;, function() {&#xA;  fetchData();&#xA;});&#xA;&#xA;// 格式化文件大小&#xA;function formatFileSize(size) {&#xA;  if (size &lt; 1024) {&#xA;    return size + &#39;B&#39;;&#xA;  } else if (size &lt; 1024 * 1024) {&#xA;    return (size / 1024).toFixed(2) + &#39;KB&#39;;&#xA;  } else if (size &lt; 1024 * 1024 * 1024) {&#xA;    return (size / (1024 * 1024)).toFixed(2) + &#39;MB&#39;;&#xA;  } else {&#xA;    return (size / (1024 * 1024 * 1024)).toFixed(2) + &#39;GB&#39;;&#xA;  }&#xA;}&#xA;&#xA;// 格式化时间&#xA;function formatTime(time) {&#xA;  if (!time) return &#39;&#39;;&#xA;  return new Date(time).toLocaleString(&#39;zh-CN&#39;);&#xA;}&#xA;&#xA;// 获取预览图片URL&#xA;function getPreviewImageUrl(url) {&#xA;  if (!url) return &#39;&#39;;&#xA;  // 将文件后缀的最后一个点替换为 _thumbn.&#xA;  url = url.replace(/\.\w+$/, &#39;_thumb$&amp;&#39;);&#xA;  // 替换http://为https://&#xA;  url = url.replace(&#39;http://&#39;, &#39;https://&#39;);&#xA;  return url.replace(&#39;https://&#39;, &#39;https://file.cncfstack.com/&#39;);&#xA;}&#xA;&#xA;function getSvgUrl(url) {&#xA;  if (!url) return &#39;&#39;;&#xA;  url = url.replace(&#39;http://&#39;, &#39;https://&#39;);&#xA;  return url.replace(&#39;https://&#39;, &#39;https://file.cncfstack.com/&#39;);&#xA;}&#xA;&#xA;// 处理分页大小变化&#xA;function handleSizeChange(event) {&#xA;  pageSize = parseInt(event.target.value);&#xA;  currentPage = 1;&#xA;  fetchData();&#xA;}&#xA;&#xA;// 处理当前页变化&#xA;function handleCurrentChange(page) {&#xA;  currentPage = page;&#xA;  fetchData();&#xA;}&#xA;&#xA;// 获取任务列表&#xA;function fetchData() {&#xA;  const params = new URLSearchParams({&#xA;    page: currentPage,&#xA;    page_size: pageSize,&#xA;    sync_status: &#39;success&#39;,&#xA;    order_by: &#39;created_at DESC&#39;,&#xA;    file_type: &#39;logo&#39;&#xA;  });&#xA;  &#xA;  if (searchKeyword) {&#xA;    params.append(&#39;search_keyword&#39;, searchKeyword);&#xA;  }&#xA;  &#xA;  const url = `https://server.cs.cncfstack.com/api/v1/resources/file/filesync?${params.toString()}`;&#xA;  &#xA;  fetch(url)&#xA;    .then(response =&gt; response.json())&#xA;    .then(data =&gt; {&#xA;      tableData = data.data || [];&#xA;      totalTasks = data.total || 0;&#xA;      renderPage();&#xA;    })&#xA;    .catch(error =&gt; {&#xA;      console.error(&#39;获取Logo文件失败:&#39;, error);&#xA;      dynamicContent.innerHTML = `&#xA;        &lt;div class=&#34;error-message&#34;&gt;&#xA;          &lt;p&gt;获取Logo文件失败，请稍后重试。&lt;/p&gt;</description>
    </item>
    <item>
      <title>V. 构建，发布，运行</title>
      <link>https://cncfstack.com/p/12factor/docs/build-release-run/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/build-release-run/</guid>
      <description>&lt;h2 id=&#34;严格分离构建和运行&#34;&gt;严格分离构建和运行&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e4%b8%a5%e6%a0%bc%e5%88%86%e7%a6%bb%e6%9e%84%e5%bb%ba%e5%92%8c%e8%bf%90%e8%a1%8c&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;./codebase&#34;&gt;基准代码&lt;/a&gt; 转化为一份部署(非开发环境)需要以下三个阶段：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;em&gt;构建阶段&lt;/em&gt; 是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码，获取和打包 &lt;a href=&#34;./dependencies&#34;&gt;依赖项&lt;/a&gt;，编译成二进制文件和资源文件。&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;发布阶段&lt;/em&gt; 会将构建的结果和当前部署所需 &lt;a href=&#34;./config&#34;&gt;配置&lt;/a&gt; 相结合，并能够立刻在运行环境中投入使用。&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;运行阶段&lt;/em&gt; （或者说“运行时”）是指针对选定的发布版本，在执行环境中启动一系列应用程序 &lt;a href=&#34;./processes&#34;&gt;进程&lt;/a&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;images/release.png&#34; alt=&#34;代码被构建，然后和配置结合成为发布版本&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;12-factor 应用严格区分构建，发布，运行这三个步骤。&lt;/strong&gt; 举例来说，直接修改处于运行状态的代码是非常不可取的做法，因为这些修改很难再同步回构建步骤。&lt;/p&gt;&#xA;&lt;p&gt;部署工具通常都提供了发布管理工具，最引人注目的功能是退回至较旧的发布版本。比如， &lt;a href=&#34;https://github.com/capistrano/capistrano/wiki&#34;&gt;Capistrano&lt;/a&gt;  将所有发布版本都存储在一个叫 &lt;code&gt;releases&lt;/code&gt; 的子目录中，当前的在线版本只需映射至对应的目录即可。该工具的 &lt;code&gt;rollback&lt;/code&gt; 命令可以很容易地实现回退版本的功能。&lt;/p&gt;&#xA;&lt;p&gt;每一个发布版本必须对应一个唯一的发布 ID，例如可以使用发布时的时间戳（&lt;code&gt;2011-04-06-20:32:17&lt;/code&gt;），亦或是一个增长的数字（&lt;code&gt;v100&lt;/code&gt;）。发布的版本就像一本只能追加的账本，一旦发布就不可修改，任何的变动都应该产生一个新的发布版本。&lt;/p&gt;&#xA;&lt;p&gt;新的代码在部署之前，需要开发人员触发构建操作。但是，运行阶段不一定需要人为触发，而是可以自动进行。如服务器重启，或是进程管理器重启了一个崩溃的进程。因此，运行阶段应该保持尽可能少的模块，这样假设半夜发生系统故障而开发人员又捉襟见肘也不会引起太大问题。构建阶段是可以相对复杂一些的，因为错误信息能够立刻展示在开发人员面前，从而得到妥善处理。&lt;/p&gt;</description>
    </item>
    <item>
      <title>VI. 进程</title>
      <link>https://cncfstack.com/p/12factor/docs/processes/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/processes/</guid>
      <description>&lt;h2 id=&#34;以一个或多个无状态进程运行应用&#34;&gt;以一个或多个无状态进程运行应用&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e4%bb%a5%e4%b8%80%e4%b8%aa%e6%88%96%e5%a4%9a%e4%b8%aa%e6%97%a0%e7%8a%b6%e6%80%81%e8%bf%9b%e7%a8%8b%e8%bf%90%e8%a1%8c%e5%ba%94%e7%94%a8&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;运行环境中，应用程序通常是以一个和多个 &lt;em&gt;进程&lt;/em&gt; 运行的。&lt;/p&gt;&#xA;&lt;p&gt;最简单的场景中，代码是一个独立的脚本，运行环境是开发人员自己的笔记本电脑，进程由一条命令行（例如&lt;code&gt;python my_script.py&lt;/code&gt;）。另外一个极端情况是，复杂的应用可能会使用很多 &lt;a href=&#34;./concurrency&#34;&gt;进程类型&lt;/a&gt; ，也就是零个或多个进程实例。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;12-Factor 应用的进程必须无状态且 &lt;a href=&#34;http://en.wikipedia.org/wiki/Shared_nothing_architecture&#34;&gt;无共享&lt;/a&gt; 。&lt;/strong&gt; 任何需要持久化的数据都要存储在 &lt;a href=&#34;./backing-services&#34;&gt;后端服务&lt;/a&gt; 内，比如数据库。&lt;/p&gt;&#xA;&lt;p&gt;内存区域或磁盘空间可以作为进程在做某种事务型操作时的缓存，例如下载一个很大的文件，对其操作并将结果写入数据库的过程。12-Factor应用根本不用考虑这些缓存的内容是不是可以保留给之后的请求来使用，这是因为应用启动了多种类型的进程，将来的请求多半会由其他进程来服务。即使在只有一个进程的情形下，先前保存的数据（内存或文件系统中）也会因为重启（如代码部署、配置更改、或运行环境将进程调度至另一个物理区域执行）而丢失。&lt;/p&gt;&#xA;&lt;p&gt;源文件打包工具（&lt;a href=&#34;http://documentcloud.github.com/jammit/&#34;&gt;Jammit&lt;/a&gt;, &lt;a href=&#34;http://django-compressor.readthedocs.org/&#34;&gt;django-compressor&lt;/a&gt;） 使用文件系统来缓存编译过的源文件。12-Factor 应用更倾向于在 &lt;a href=&#34;./build-release-run&#34;&gt;构建步骤&lt;/a&gt; 做此动作——正如 &lt;a href=&#34;http://guides.rubyonrails.org/asset_pipeline.html&#34;&gt;Rails资源管道&lt;/a&gt; ，而不是在运行阶段。&lt;/p&gt;&#xA;&lt;p&gt;一些互联网系统依赖于 “&lt;a href=&#34;http://en.wikipedia.org/wiki/Load_balancing_%28computing%29#Persistence&#34;&gt;粘性 session &lt;/a&gt;”， 这是指将用户 session 中的数据缓存至某进程的内存中，并将同一用户的后续请求路由到同一个进程。粘性 session 是 12-Factor 极力反对的。Session 中的数据应该保存在诸如 &lt;a href=&#34;http://memcached.org/&#34;&gt;Memcached&lt;/a&gt; 或 &lt;a href=&#34;http://redis.io/&#34;&gt;Redis&lt;/a&gt; 这样的带有过期时间的缓存中。&lt;/p&gt;</description>
    </item>
    <item>
      <title>VII. 端口绑定</title>
      <link>https://cncfstack.com/p/12factor/docs/port-binding/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/port-binding/</guid>
      <description>&lt;h2 id=&#34;通过端口绑定port-binding来提供服务&#34;&gt;通过端口绑定(&lt;em&gt;Port binding&lt;/em&gt;)来提供服务&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e9%80%9a%e8%bf%87%e7%ab%af%e5%8f%a3%e7%bb%91%e5%ae%9aport-binding%e6%9d%a5%e6%8f%90%e4%be%9b%e6%9c%8d%e5%8a%a1&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;互联网应用有时会运行于服务器的容器之中。例如 PHP 经常作为 &lt;a href=&#34;http://httpd.apache.org/&#34;&gt;Apache HTTPD&lt;/a&gt; 的一个模块来运行，正如 Java 运行于 &lt;a href=&#34;http://tomcat.apache.org/&#34;&gt;Tomcat&lt;/a&gt; 。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;12-Factor 应用完全自我加载&lt;/strong&gt; 而不依赖于任何网络服务器就可以创建一个面向网络的服务。互联网应用 &lt;strong&gt;通过端口绑定来提供服务&lt;/strong&gt; ，并监听发送至该端口的请求。&lt;/p&gt;&#xA;&lt;p&gt;本地环境中，开发人员通过类似&lt;code&gt;http://localhost:5000/&lt;/code&gt;的地址来访问服务。在线上环境中，请求统一发送至公共域名而后路由至绑定了端口的网络进程。&lt;/p&gt;&#xA;&lt;p&gt;通常的实现思路是，将网络服务器类库通过 &lt;a href=&#34;./dependencies&#34;&gt;依赖声明&lt;/a&gt; 载入应用。例如，Python 的 &lt;a href=&#34;http://www.tornadoweb.org/&#34;&gt;Tornado&lt;/a&gt;, Ruby 的&lt;a href=&#34;http://code.macournoyer.com/thin/&#34;&gt;Thin&lt;/a&gt; , Java 以及其他基于 JVM 语言的 &lt;a href=&#34;http://www.eclipse.org/jetty/&#34;&gt;Jetty&lt;/a&gt;。完全由 &lt;em&gt;用户端&lt;/em&gt; ，确切的说应该是应用的代码，发起请求。和运行环境约定好绑定的端口即可处理这些请求。&lt;/p&gt;&#xA;&lt;p&gt;HTTP 并不是唯一一个可以由端口绑定提供的服务。其实几乎所有服务器软件都可以通过进程绑定端口来等待请求。例如，使用 &lt;a href=&#34;http://xmpp.org/&#34;&gt;XMPP&lt;/a&gt; 的 &lt;a href=&#34;http://www.ejabberd.im/&#34;&gt;ejabberd&lt;/a&gt;  ， 以及使用 &lt;a href=&#34;http://redis.io/topics/protocol&#34;&gt;Redis 协议&lt;/a&gt; 的 &lt;a href=&#34;http://redis.io/&#34;&gt;Redis&lt;/a&gt; 。&lt;/p&gt;&#xA;&lt;p&gt;还要指出的是，端口绑定这种方式也意味着一个应用可以成为另外一个应用的 &lt;a href=&#34;./backing-services&#34;&gt;后端服务&lt;/a&gt; ，调用方将服务方提供的相应 URL 当作资源存入 &lt;a href=&#34;./config&#34;&gt;配置&lt;/a&gt; 以备将来调用。&lt;/p&gt;</description>
    </item>
    <item>
      <title>VIII. 并发</title>
      <link>https://cncfstack.com/p/12factor/docs/concurrency/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/concurrency/</guid>
      <description>&lt;h2 id=&#34;通过进程模型进行扩展&#34;&gt;通过进程模型进行扩展&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e9%80%9a%e8%bf%87%e8%bf%9b%e7%a8%8b%e6%a8%a1%e5%9e%8b%e8%bf%9b%e8%a1%8c%e6%89%a9%e5%b1%95&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;任何计算机程序，一旦启动，就会生成一个或多个进程。互联网应用采用多种进程运行方式。例如，PHP 进程作为 Apache 的子进程存在，随请求按需启动。Java 进程则采取了相反的方式，在程序启动之初 JVM 就提供了一个超级进程储备了大量的系统资源(CPU 和内存)，并通过多线程实现内部的并发管理。上述 2 个例子中，进程是开发人员可以操作的最小单位。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;images/process-types.png&#34; alt=&#34;扩展表现为运行中的进程，工作多样性表现为进程类型。&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;**在 12-factor 应用中，进程是一等公民。**12-Factor 应用的进程主要借鉴于 &lt;a href=&#34;https://adam.herokuapp.com/past/2011/5/9/applying_the_unix_process_model_to_web_apps/&#34;&gt;unix 守护进程模型&lt;/a&gt; 。开发人员可以运用这个模型去设计应用架构，将不同的工作分配给不同的 &lt;em&gt;进程类型&lt;/em&gt; 。例如，HTTP 请求可以交给 web 进程来处理，而常驻的后台工作则交由 worker 进程负责。&lt;/p&gt;&#xA;&lt;p&gt;这并不包括个别较为特殊的进程，例如通过虚拟机的线程处理并发的内部运算，或是使用诸如 &lt;a href=&#34;https://github.com/eventmachine/eventmachine&#34;&gt;EventMachine&lt;/a&gt;, &lt;a href=&#34;http://twistedmatrix.com/trac/&#34;&gt;Twisted&lt;/a&gt;,  &lt;a href=&#34;http://nodejs.org/&#34;&gt;Node.js&lt;/a&gt; 的异步/事件触发模型。但一台独立的虚拟机的扩展有瓶颈（垂直扩展），所以应用程序必须可以在多台物理机器间跨进程工作。&lt;/p&gt;&#xA;&lt;p&gt;上述进程模型会在系统急需扩展时大放异彩。 &lt;a href=&#34;./processes&#34;&gt;12-Factor 应用的进程所具备的无共享，水平分区的特性&lt;/a&gt; 意味着添加并发会变得简单而稳妥。这些进程的类型以及每个类型中进程的数量就被称作 &lt;em&gt;进程构成&lt;/em&gt; 。&lt;/p&gt;&#xA;&lt;p&gt;12-Factor 应用的进程 &lt;a href=&#34;http://dustin.github.com/2010/02/28/running-processes.html&#34;&gt;不需要守护进程&lt;/a&gt; 或是写入 PID 文件。相反的，应该借助操作系统的进程管理器(例如 &lt;a href=&#34;https://www.freedesktop.org/wiki/Software/systemd/&#34;&gt;systemd&lt;/a&gt; ，分布式的进程管理云平台，或是类似 &lt;a href=&#34;http://blog.daviddollar.org/2011/05/06/introducing-foreman.html&#34;&gt;Foreman&lt;/a&gt; 的工具)，来管理 &lt;a href=&#34;./logs&#34;&gt;输出流&lt;/a&gt; ，响应崩溃的进程，以及处理用户触发的重启和关闭超级进程的请求。&lt;/p&gt;</description>
    </item>
    <item>
      <title>X. 开发环境与线上环境等价</title>
      <link>https://cncfstack.com/p/12factor/docs/dev-prod-parity/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/dev-prod-parity/</guid>
      <description>&lt;h2 id=&#34;尽可能的保持开发预发布线上环境相同&#34;&gt;尽可能的保持开发，预发布，线上环境相同&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e5%b0%bd%e5%8f%af%e8%83%bd%e7%9a%84%e4%bf%9d%e6%8c%81%e5%bc%80%e5%8f%91%e9%a2%84%e5%8f%91%e5%b8%83%e7%ba%bf%e4%b8%8a%e7%8e%af%e5%a2%83%e7%9b%b8%e5%90%8c&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;从以往经验来看，开发环境（即开发人员的本地 &lt;a href=&#34;./codebase&#34;&gt;部署&lt;/a&gt;）和线上环境（外部用户访问的真实部署）之间存在着很多差异。这些差异表现在以下三个方面：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;时间差异：&lt;/strong&gt; 开发人员正在编写的代码可能需要几天，几周，甚至几个月才会上线。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;人员差异：&lt;/strong&gt; 开发人员编写代码，运维人员部署代码。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;工具差异：&lt;/strong&gt; 开发人员或许使用 Nginx，SQLite，OS X，而线上环境使用 Apache，MySQL 以及 Linux。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;12-Factor 应用想要做到 &lt;a href=&#34;http://avc.com/2011/02/continuous-deployment/&#34;&gt;持续部署&lt;/a&gt; 就必须缩小本地与线上差异。&lt;/strong&gt; 再回头看上面所描述的三个差异:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;缩小时间差异：开发人员可以几小时，甚至几分钟就部署代码。&lt;/li&gt;&#xA;&lt;li&gt;缩小人员差异：开发人员不只要编写代码，更应该密切参与部署过程以及代码在线上的表现。&lt;/li&gt;&#xA;&lt;li&gt;缩小工具差异：尽量保证开发环境以及线上环境的一致性。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;将上述总结变为一个表格如下：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;tr&gt;&#xA;    &lt;th&gt;&lt;/th&gt;&#xA;    &lt;th&gt;传统应用&lt;/th&gt;&#xA;    &lt;th&gt;12-Factor 应用&lt;/th&gt;&#xA;  &lt;/tr&gt;&#xA;  &lt;tr&gt;&#xA;    &lt;th&gt;每次部署间隔&lt;/th&gt;&#xA;    &lt;td&gt;数周&lt;/td&gt;&#xA;    &lt;td&gt;几小时&lt;/td&gt;&#xA;  &lt;/tr&gt;&#xA;  &lt;tr&gt;&#xA;    &lt;th&gt;开发人员 vs 运维人员&lt;/th&gt;&#xA;    &lt;td&gt;不同的人&lt;/td&gt;&#xA;    &lt;td&gt;相同的人&lt;/td&gt;&#xA;  &lt;/tr&gt;&#xA;  &lt;tr&gt;&#xA;    &lt;th&gt;开发环境 vs 线上环境&lt;/th&gt;&#xA;    &lt;td&gt;不同&lt;/td&gt;&#xA;    &lt;td&gt;尽量接近&lt;/td&gt;&#xA;  &lt;/tr&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;&lt;a href=&#34;./backing-services&#34;&gt;后端服务&lt;/a&gt; 是保持开发与线上等价的重要部分，例如数据库，队列系统，以及缓存。许多语言都提供了简化获取后端服务的类库，例如不同类型服务的 &lt;em&gt;适配器&lt;/em&gt; 。下列表格提供了一些例子。&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;tr&gt;&#xA;    &lt;th&gt;类型&lt;/th&gt;&#xA;    &lt;th&gt;语言&lt;/th&gt;&#xA;    &lt;th&gt;类库&lt;/th&gt;&#xA;    &lt;th&gt;适配器&lt;/th&gt;&#xA;  &lt;/tr&gt;&#xA;  &lt;tr&gt;&#xA;    &lt;td&gt;数据库&lt;/td&gt;&#xA;    &lt;td&gt;Ruby/Rails&lt;/td&gt;&#xA;    &lt;td&gt;ActiveRecord&lt;/td&gt;&#xA;    &lt;td&gt;MySQL, PostgreSQL, SQLite&lt;/td&gt;&#xA;  &lt;/tr&gt;&#xA;  &lt;tr&gt;&#xA;    &lt;td&gt;队列&lt;/td&gt;&#xA;    &lt;td&gt;Python/Django&lt;/td&gt;&#xA;    &lt;td&gt;Celery&lt;/td&gt;&#xA;    &lt;td&gt;RabbitMQ, Beanstalkd, Redis&lt;/td&gt;&#xA;  &lt;/tr&gt;&#xA;  &lt;tr&gt;&#xA;    &lt;td&gt;缓存&lt;/td&gt;&#xA;    &lt;td&gt;Ruby/Rails&lt;/td&gt;&#xA;    &lt;td&gt;ActiveSupport::Cache&lt;/td&gt;&#xA;    &lt;td&gt;Memory, filesystem, Memcached&lt;/td&gt;&#xA;  &lt;/tr&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;开发人员有时会觉得在本地环境中使用轻量的后端服务具有很强的吸引力，而那些更重量级的健壮的后端服务应该使用在生产环境。例如，本地使用 SQLite 线上使用 PostgreSQL；又如本地缓存在进程内存中而线上存入 Memcached。&lt;/p&gt;</description>
    </item>
    <item>
      <title>XI. 日志</title>
      <link>https://cncfstack.com/p/12factor/docs/logs/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/logs/</guid>
      <description>&lt;h2 id=&#34;把日志当作事件流&#34;&gt;把日志当作事件流&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e6%8a%8a%e6%97%a5%e5%bf%97%e5%bd%93%e4%bd%9c%e4%ba%8b%e4%bb%b6%e6%b5%81&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;em&gt;日志&lt;/em&gt; 使得应用程序运行的动作变得透明。在基于服务器的环境中，日志通常被写在硬盘的一个文件里，但这只是一种输出格式。&lt;/p&gt;&#xA;&lt;p&gt;日志应该是 &lt;a href=&#34;https://adam.herokuapp.com/past/2011/4/1/logs_are_streams_not_files/&#34;&gt;事件流&lt;/a&gt; 的汇总，将所有运行中进程和后端服务的输出流按照时间顺序收集起来。尽管在回溯问题时可能需要看很多行，日志最原始的格式确实是一个事件一行。日志没有确定开始和结束，但随着应用在运行会持续的增加。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;12-factor应用本身从不考虑存储自己的输出流。&lt;/strong&gt; 不应该试图去写或者管理日志文件。相反，每一个运行的进程都会直接的标准输出（&lt;code&gt;stdout&lt;/code&gt;）事件流。开发环境中，开发人员可以通过这些数据流，实时在终端看到应用的活动。&lt;/p&gt;&#xA;&lt;p&gt;在预发布或线上部署中，每个进程的输出流由运行环境截获，并将其他输出流整理在一起，然后一并发送给一个或多个最终的处理程序，用于查看或是长期存档。这些存档路径对于应用来说不可见也不可配置，而是完全交给程序的运行环境管理。类似 &lt;a href=&#34;https://github.com/heroku/logplex&#34;&gt;Logplex&lt;/a&gt; 和 &lt;a href=&#34;https://github.com/fluent/fluentd&#34;&gt;Fluentd&lt;/a&gt; 的开源工具可以达到这个目的。&lt;/p&gt;&#xA;&lt;p&gt;这些事件流可以输出至文件，或者在终端实时观察。最重要的，输出流可以发送到 &lt;a href=&#34;http://www.splunk.com/&#34;&gt;Splunk&lt;/a&gt; 这样的日志索引及分析系统，或 &lt;a href=&#34;http://hive.apache.org/&#34;&gt;Hadoop/Hive&lt;/a&gt; 这样的通用数据存储系统。这些系统为查看应用的历史活动提供了强大而灵活的功能，包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;找出过去一段时间特殊的事件。&lt;/li&gt;&#xA;&lt;li&gt;图形化一个大规模的趋势，比如每分钟的请求量。&lt;/li&gt;&#xA;&lt;li&gt;根据用户定义的条件实时触发警报，比如每分钟的报错超过某个警戒线。&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>XII. 管理进程</title>
      <link>https://cncfstack.com/p/12factor/docs/admin-processes/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/docs/admin-processes/</guid>
      <description>&lt;h2 id=&#34;后台管理任务当作一次性进程运行&#34;&gt;后台管理任务当作一次性进程运行&lt;a class=&#34;td-heading-self-link&#34; href=&#34;#%e5%90%8e%e5%8f%b0%e7%ae%a1%e7%90%86%e4%bb%bb%e5%8a%a1%e5%bd%93%e4%bd%9c%e4%b8%80%e6%ac%a1%e6%80%a7%e8%bf%9b%e7%a8%8b%e8%bf%90%e8%a1%8c&#34; aria-label=&#34;Heading self-link&#34;&gt;&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;./concurrency&#34;&gt;进程构成&lt;/a&gt;（process formation）是指用来处理应用的常规业务（比如处理 web 请求）的一组进程。与此不同，开发人员经常希望执行一些管理或维护应用的一次性任务，例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;运行数据移植（Django 中的 &lt;code&gt;manage.py migrate&lt;/code&gt;, Rails 中的 &lt;code&gt;rake db:migrate&lt;/code&gt;）。&lt;/li&gt;&#xA;&lt;li&gt;运行一个控制台（也被称为 &lt;a href=&#34;http://en.wikipedia.org/wiki/Read-eval-print_loop&#34;&gt;REPL&lt;/a&gt; shell），来执行一些代码或是针对线上数据库做一些检查。大多数语言都通过解释器提供了一个 REPL 工具（&lt;code&gt;python&lt;/code&gt; 或 &lt;code&gt;perl&lt;/code&gt;） ，或是其他命令（Ruby 使用 &lt;code&gt;irb&lt;/code&gt;, Rails 使用 &lt;code&gt;rails console&lt;/code&gt;）。&lt;/li&gt;&#xA;&lt;li&gt;运行一些提交到代码仓库的一次性脚本。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;一次性管理进程应该和正常的 &lt;a href=&#34;./processes&#34;&gt;常驻进程&lt;/a&gt; 使用同样的环境。这些管理进程和任何其他的进程一样使用相同的 &lt;a href=&#34;./codebase&#34;&gt;代码&lt;/a&gt; 和 &lt;a href=&#34;./config&#34;&gt;配置&lt;/a&gt; ，基于某个 &lt;a href=&#34;./build-release-run&#34;&gt;发布版本&lt;/a&gt; 运行。后台管理代码应该随其他应用程序代码一起发布，从而避免同步问题。&lt;/p&gt;&#xA;&lt;p&gt;所有进程类型应该使用同样的 &lt;a href=&#34;./dependencies&#34;&gt;依赖隔离&lt;/a&gt; 技术。例如，如果Ruby的web进程使用了命令 &lt;code&gt;bundle exec thin start&lt;/code&gt; ，那么数据库移植应使用 &lt;code&gt;bundle exec rake db:migrate&lt;/code&gt; 。同样的，如果一个 Python 程序使用了 Virtualenv，则需要在运行 Tornado Web 服务器和任何 &lt;code&gt;manage.py&lt;/code&gt; 管理进程时引入 &lt;code&gt;bin/python&lt;/code&gt; 。&lt;/p&gt;&#xA;&lt;p&gt;12-factor 尤其青睐那些提供了 REPL shell 的语言，因为那会让运行一次性脚本变得简单。在本地部署中，开发人员直接在命令行使用 shell 命令调用一次性管理进程。在线上部署中，开发人员依旧可以使用ssh或是运行环境提供的其他机制来运行这样的进程。&lt;/p&gt;</description>
    </item>
    <item>
      <title>代码仓库</title>
      <link>https://cncfstack.com/p/12factor/code/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/code/</guid>
      <description>&lt;script type=&#34;text/javascript&#34;&gt;&#xA;    function resizeIframe(iframe) {&#xA;      iframe.height = iframe.contentWindow.document.body.scrollHeight + &#34;px&#34;;&#xA;    }&#xA;  &lt;/script&gt;  &#xA;&#xA;&lt;iframe id=&#34;iframe-id&#34; class=&#34;iframe-container&#34; src=&#34;https://gitea.cncfstack.com/twelve-factor&#34; width=&#34;100%&#34; name=&#34;iframe-name&#34; style=&#34;min-height:98vh; border:none;&#34; onload=&#34;resizeIframe(this)&#34; referrerpolicy=&#34;no-referrer&#34;&gt;&#xA;  &lt;p&gt;Your browser can not display embedded frames. You can access the embedded page via the following link: &lt;a href=&#34;https://gitea.cncfstack.com/twelve-factor&#34;&gt;https://gitea.cncfstack.com/twelve-factor&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/iframe&gt;&#xA;&#xA;&lt;style&gt;&#xA;.iframe-container {&#xA;  margin-top: 15px;&#xA;}&#xA;&lt;/style&gt;</description>
    </item>
    <item>
      <title>博客</title>
      <link>https://cncfstack.com/p/12factor/news/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/news/</guid>
      <description>&lt;div id=&#34;blog-app&#34;&gt;&#xA;  &lt;!-- 加载状态 --&gt;&#xA;  &lt;div id=&#34;loading-state&#34; class=&#34;loading-state&#34;&gt;&#xA;    &lt;div class=&#34;loading-spinner&#34;&gt;&lt;/div&gt;&#xA;    &lt;p&gt;文档加载中...&lt;/p&gt;&#xA;  &lt;/div&gt;&#xA;  &lt;iframe &#xA;    id=&#34;blog-iframe&#34;&#xA;    src=&#34;&#34;&#xA;    class=&#34;full-width-iframe&#34;&#xA;    scrolling=&#34;auto&#34;&#xA;    onload=&#34;onIframeLoad()&#34;&#xA;  &gt;&lt;/iframe&gt;&#xA;&lt;/div&gt;&#xA;&lt;style&gt;&#xA;/* 原有样式保持不变 */&#xA;.image-list-container {&#xA;  max-width: 1200px;&#xA;  margin: 2rem auto;&#xA;  padding: 0 1rem;&#xA;}&#xA;&#xA;.image-list-title {&#xA;  text-align: center;&#xA;  margin-bottom: 2rem;&#xA;  color: #333;&#xA;  font-size: 1.8rem;&#xA;}&#xA;&#xA;.image-grid {&#xA;  display: grid;&#xA;  grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));&#xA;  gap: 1.5rem;&#xA;}&#xA;&#xA;.image-card {&#xA;  border: 1px solid #e1e8ed;&#xA;  border-radius: 8px;&#xA;  overflow: hidden;&#xA;  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);&#xA;  transition: transform 0.3s ease, box-shadow 0.3s ease;&#xA;  background: white;&#xA;  cursor: pointer;&#xA;}&#xA;&#xA;.image-card:hover {&#xA;  transform: translateY(-5px);&#xA;  box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);&#xA;}&#xA;&#xA;.card-link {&#xA;  text-decoration: none;&#xA;  color: inherit;&#xA;}&#xA;&#xA;.card-header {&#xA;  background-color: #f5f8fa;&#xA;  padding: 1rem;&#xA;  border-bottom: 1px solid #e1e8ed;&#xA;}&#xA;&#xA;.card-title {&#xA;  margin: 0;&#xA;  font-size: 1.2rem;&#xA;  color: #1da1f2;&#xA;  font-weight: 600;&#xA;}&#xA;&#xA;.card-body {&#xA;  padding: 1rem;&#xA;}&#xA;&#xA;.vendor-info {&#xA;  display: flex;&#xA;  align-items: center;&#xA;  margin-bottom: 0.8rem;&#xA;}&#xA;&#xA;.vendor-icon {&#xA;  width: 32px;&#xA;  height: 32px;&#xA;  background-color: #1da1f2;&#xA;  border-radius: 50%;&#xA;  display: flex;&#xA;  align-items: center;&#xA;  justify-content: center;&#xA;  color: white;&#xA;  font-weight: bold;&#xA;  margin-right: 0.8rem;&#xA;}&#xA;&#xA;.vendor-name {&#xA;  font-weight: 500;&#xA;  color: #333;&#xA;}&#xA;&#xA;.repo-info {&#xA;  background-color: #f8f9fa;&#xA;  padding: 0.8rem;&#xA;  border-radius: 4px;&#xA;  font-family: &#39;Courier New&#39;, monospace;&#xA;  font-size: 0.9rem;&#xA;  color: #333;&#xA;  word-break: break-all;&#xA;  margin-bottom: 0;&#xA;}&#xA;&#xA;.error-message {&#xA;  text-align: center;&#xA;  color: #e02d2d;&#xA;  padding: 2rem;&#xA;  font-size: 1.1rem;&#xA;}&#xA;&#xA;.loading-message {&#xA;  text-align: center;&#xA;  padding: 2rem;&#xA;  font-size: 1.1rem;&#xA;  color: #657786;&#xA;}&#xA;&#xA;@media (max-width: 768px) {&#xA;  .image-grid {&#xA;    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));&#xA;    gap: 1rem;&#xA;  }&#xA;  &#xA;  .image-list-title {&#xA;    font-size: 1.5rem;&#xA;  }&#xA;}&#xA;&#xA;/* 新增博客页面样式 */&#xA;.blog-page {&#xA;  margin-top: -60px;&#xA;  width: 100%;&#xA;}&#xA;&#xA;.full-width-iframe {&#xA;  width: 100%;&#xA;  border: none;&#xA;  overflow: hidden;&#xA;  min-height: 600px;&#xA;}&#xA;&#xA;.loading-spinner {&#xA;  width: 40px;&#xA;  height: 40px;&#xA;  border: 4px solid #e9ecef;&#xA;  border-top: 4px solid #007bff;&#xA;  border-radius: 50%;&#xA;  animation: spin 1s linear infinite;&#xA;  margin: 0 auto;&#xA;}&#xA;&#xA;@keyframes spin {&#xA;  0% { transform: rotate(0deg); }&#xA;  100% { transform: rotate(360deg); }&#xA;}&#xA;&#xA;.loading-state {&#xA;  text-align: center;&#xA;  padding: 2rem;&#xA;}&#xA;&lt;/style&gt;&#xA;&lt;script&gt;&#xA;// 初始化 iframe URL&#xA;document.addEventListener(&#39;DOMContentLoaded&#39;, function() {&#xA;  const iframe = document.getElementById(&#39;blog-iframe&#39;);&#xA;  const currentYear = new Date().getFullYear();&#xA;  iframe.src = `https://cncfstack.com/b/tags/12factor`;&#xA;  // 设置初始高度&#xA;  iframe.style.height = window.innerHeight + &#39;px&#39;;&#xA;  &#xA;  // 添加 visibilitychange 事件监听器&#xA;  document.addEventListener(&#39;visibilitychange&#39;, handleVisibilityChange);&#xA;});&#xA;&#xA;function hideInternalNav() {&#xA;  const iframe = document.getElementById(&#39;blog-iframe&#39;);&#xA;  if (!iframe) return;&#xA;&#xA;  try {&#xA;    const iframeDoc = iframe.contentDocument;&#xA;    if (iframeDoc) {&#xA;      // 隐藏导航栏元素&#xA;      const navElement = iframeDoc.querySelector(&#39;nav.td-navbar&#39;);&#xA;      if (navElement) {&#xA;        navElement.style.display = &#39;none&#39;;&#xA;      }&#xA;&#xA;      // 隐藏 header 元素&#xA;      const headerElement = iframeDoc.querySelector(&#39;header&#39;);&#xA;      if (headerElement) {&#xA;        headerElement.style.display = &#39;none&#39;;&#xA;      }&#xA;&#xA;      // 隐藏页面底部元素&#xA;      const navFooterElement = iframeDoc.querySelector(&#39;footer.td-footer&#39;);&#xA;      if (navFooterElement) {&#xA;        navFooterElement.style.display = &#39;none&#39;;&#xA;      }&#xA;    }&#xA;  } catch (e) {&#xA;    console.log(&#39;无法访问 iframe 内容（可能是跨域限制）&#39;);&#xA;  }&#xA;}&#xA;&#xA;function setIframeHeight() {&#xA;  const iframe = document.getElementById(&#39;blog-iframe&#39;);&#xA;  if (!iframe) return;&#xA;&#xA;  try {&#xA;    const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;&#xA;    if (iframeDoc) {&#xA;      // 延迟执行以确保样式已应用&#xA;      setTimeout(() =&gt; {&#xA;        const height = Math.max(&#xA;          iframeDoc.body.scrollHeight,&#xA;          iframeDoc.documentElement.scrollHeight,&#xA;          iframeDoc.body.offsetHeight,&#xA;          iframeDoc.documentElement.offsetHeight,&#xA;          iframeDoc.body.clientHeight,&#xA;          iframeDoc.documentElement.clientHeight&#xA;        );&#xA;&#xA;        iframe.style.height = height + &#39;px&#39;;&#xA;      }, 100);&#xA;    }&#xA;  } catch (e) {&#xA;    // 跨域情况下的备选方案&#xA;    iframe.style.height = &#39;1200px&#39;;&#xA;  }&#xA;}&#xA;&#xA;function onIframeLoad() {&#xA;  hideInternalNav();&#xA;  setIframeHeight();&#xA;  &#xA;  // 隐藏加载状态&#xA;  const loadingState = document.getElementById(&#39;loading-state&#39;);&#xA;  if (loadingState) {&#xA;    loadingState.style.display = &#39;none&#39;;&#xA;  }&#xA;}&#xA;&#xA;function handleVisibilityChange() {&#xA;  const iframe = document.getElementById(&#39;blog-iframe&#39;);&#xA;  if (!document.hidden &amp;&amp; iframe) {&#xA;    // 页面变为可见时重新调整 iframe 高度&#xA;    setTimeout(() =&gt; {&#xA;      setIframeHeight();&#xA;    }, 300);&#xA;  }&#xA;}&#xA;&#xA;// 窗口大小改变时调整 iframe 高度&#xA;window.addEventListener(&#39;resize&#39;, function() {&#xA;  const iframe = document.getElementById(&#39;blog-iframe&#39;);&#xA;  if (iframe) {&#xA;    setIframeHeight();&#xA;  }&#xA;});&#xA;&lt;/script&gt;</description>
    </item>
    <item>
      <title>搜索结果</title>
      <link>https://cncfstack.com/p/12factor/search/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/search/</guid>
      <description></description>
    </item>
    <item>
      <title>官方网站</title>
      <link>https://cncfstack.com/p/12factor/website/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/website/</guid>
      <description>&lt;section id=&#34;td-cover-block-0&#34; class=&#34;row td-cover-block td-cover-block--height-auto js-td-cover td-overlay td-overlay--dark -bg-primary&#34;&gt;&#xA;  &lt;div class=&#34;col-12&#34;&gt;&#xA;    &lt;div class=&#34;container td-overlay__inner&#34;&gt;&#xA;      &lt;div class=&#34;text-center&#34;&gt;&#xA;        &lt;h1 class=&#34;display-1 mt-0 mt-md-5 pb-4&#34;&gt;12factor 官方网站&lt;/h1&gt;&#xA;        &#xA;        &lt;div class=&#34;pt-3 lead&#34;&gt;&#xA;          &#xA;              软件项目第一手资料除了&lt;strong&gt;源码&lt;/strong&gt;，就是&lt;strong&gt;官网&lt;/strong&gt;&#xA;          &#xA;        &lt;/div&gt;&#xA;      &lt;/div&gt;&#xA;    &lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;  &#xA;&lt;/section&gt;&#xA;&#xA;&lt;div&gt;&lt;a id=&#34;td-block-1&#34; class=&#34;td-offset-anchor&#34;&gt;&lt;/a&gt;&lt;/div&gt;&#xA;&lt;section class=&#34;row td-box td-box--dark td-box--height-auto&#34;&gt;&#xA;&lt;div class=&#34;col&#34;&gt;&#xA;&lt;div class=&#34;row&#34;&gt;&#xA;&#xA;&#xA;&lt;div class=&#34;col-lg-4 mb-5 mb-lg-0 text-center&#34;&gt;&#xA;&lt;div class=&#34;mb-4 h1&#34;&gt;&#xA;  &lt;i class=&#34;fas fa-lightbulb&#34;&gt;&lt;/i&gt;&#xA;&lt;/div&gt;&#xA;&lt;h4 class=&#34;h3&#34;&gt;官网镜像（中文）&lt;/h4&gt;&#xA;&lt;div class=&#34;mb-0&#34;&gt;&#xA;&lt;p&gt;项目实际官网，由该项目的社区共同维护，是最新最权威的项目网站&lt;/p&gt;&#xA;&lt;div class=&#34;mx-auto&#34;&gt;&#xA;&#x9;&lt;a class=&#34;btn btn-lg btn-primary me-3 mb-4&#34; href=&#34;https://12factor.net/zh_cn/&#34; target=&#34;_blank&#34;&gt;&#xA;&#x9;&#x9;访问网站 &lt;i class=&#34;fa-solid fa-circle-right ms-2&#34;&gt;&lt;/i&gt;&#xA;&#x9;&lt;/a&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&#xA;&lt;div class=&#34;col-lg-4 mb-5 mb-lg-0 text-center&#34;&gt;&#xA;&lt;div class=&#34;mb-4 h1&#34;&gt;&#xA;  &lt;i class=&#34;fas fa-lightbulb&#34;&gt;&lt;/i&gt;&#xA;&lt;/div&gt;&#xA;&lt;h4 class=&#34;h3&#34;&gt;官网&lt;/h4&gt;&#xA;&lt;div class=&#34;mb-0&#34;&gt;&#xA;&lt;p&gt;项目实际官网，由该项目的社区共同维护，是最新最权威的项目网站&lt;/p&gt;&#xA;&lt;div class=&#34;mx-auto&#34;&gt;&#xA;&#x9;&lt;a class=&#34;btn btn-lg btn-primary me-3 mb-4&#34; href=&#34;https://gitea.cncfstack.com/heroku/12factor&#34; target=&#34;_blank&#34;&gt;&#xA;&#x9;&#x9;访问网站 &lt;i class=&#34;fa-solid fa-circle-right ms-2&#34;&gt;&lt;/i&gt;&#xA;&#x9;&lt;/a&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;/section&gt;</description>
    </item>
    <item>
      <title>论坛</title>
      <link>https://cncfstack.com/p/12factor/discourse/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://cncfstack.com/p/12factor/discourse/</guid>
      <description>&lt;section id=&#34;td-cover-block-0&#34; class=&#34;row td-cover-block td-cover-block--height-full js-td-cover td-overlay td-overlay--dark -bg-primary&#34;&gt;&#xA;  &lt;div class=&#34;col-12&#34;&gt;&#xA;    &lt;div class=&#34;container td-overlay__inner&#34;&gt;&#xA;      &lt;div class=&#34;text-center&#34;&gt;&#xA;        &lt;h1 class=&#34;display-1 mt-0 mt-md-5 pb-4&#34;&gt;论坛&lt;/h1&gt;&#xA;        &#xA;        &lt;div class=&#34;pt-3 lead&#34;&gt;&#xA;          &#xA;              &lt;p&gt;开放的社区论坛，自由的技术交流&lt;/p&gt;&#xA;&lt;div class=&#34;mx-auto&#34;&gt;&#xA;&#x9;&lt;a class=&#34;btn btn-lg btn-primary me-3 mb-4&#34; href=&#34;https://discourse.cncfstack.com/tag/12factor/&#34; target=&#34;_blank&#34;&gt;&#xA;&#x9;&#x9;访问论坛 &lt;i class=&#34;fa-solid fa-circle-right ms-2&#34;&gt;&lt;/i&gt;&#xA;&#x9;&lt;/a&gt;&#xA;&lt;/div&gt;&#xA;          &#xA;        &lt;/div&gt;&#xA;      &lt;/div&gt;&#xA;    &lt;/div&gt;&#xA;  &lt;/div&gt;&#xA;  &#xA;&lt;/section&gt;</description>
    </item>
  </channel>
</rss>
