<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[迪加]]></title><description><![CDATA[记录自己遇到的大小事~]]></description><link>https://dick.plus</link><generator>Yohaku (https://github.com/Innei/Yohaku)</generator><lastBuildDate>Tue, 28 Apr 2026 14:39:08 GMT</lastBuildDate><atom:link href="https://dick.plus/feed" rel="self" type="application/rss+xml"/><pubDate>Tue, 28 Apr 2026 14:39:08 GMT</pubDate><language><![CDATA[zh-CN]]></language><item><title><![CDATA[Debian 13 宝塔面板 Docker 管理无法显示容器 — 修复方案]]></title><description><![CDATA[<div><blockquote>此渲染由 Yohaku API 生成，或存排版之虞，最佳体验请往：<a href="https://dick.plus/posts/default/debian13-bt-docker-fix">https://dick.plus/posts/default/debian13-bt-docker-fix</a></blockquote><div><h1 id="debian-13--docker---">Debian 13 宝塔面板 Docker 管理无法显示容器 — 修复方案</h1><h2 id="">问题描述</h2><p>在 Debian 13 (Trixie) 下安装 Docker 后，宝塔面板的 Docker 管理页面无法显示正在运行的容器，容器列表为空。但通过命令行执行 <code>docker ps</code> 可以正常查看容器。</p><h2 id="">根本原因</h2><p>Debian 13 默认启用了 <strong>AppArmor 安全策略</strong>，该策略阻止了 <code>curl</code> 命令通过 Unix Socket 访问 <code>/var/run/docker.sock</code>。</p><p>而宝塔面板的 Docker 模块在获取容器列表、容器详情等数据时，底层代码依赖 <code>curl</code> 命令通过 Unix Socket 调用 Docker API：</p><pre class="language-python lang-python"><code class="language-python lang-python"># 宝塔原始代码（container.py）
curl -s --unix-socket /var/run/docker.sock http:/127.0.0.1/containers/json?all=1
</code></pre>
<p>由于 AppArmor 阻止了 curl 对 Unix Socket 的访问，该命令返回空数据，导致面板无法显示任何容器信息。</p><p><strong>验证方法：</strong></p><pre class="language-bash lang-bash"><code class="language-bash lang-bash"># curl 访问 Docker Socket — 无输出（被 AppArmor 阻止）
curl -s --unix-socket /var/run/docker.sock http://localhost/containers/json?all=1

# Python 访问 Docker Socket — 正常返回数据（不受 AppArmor 限制）
python3 -c &quot;
import http.client, socket
class UnixConn(http.client.HTTPConnection):
    def __init__(self, sock_path):
        super().__init__(&#x27;localhost&#x27;)
        self._sock_path = sock_path
    def connect(self):
        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.sock.connect(self._sock_path)
conn = UnixConn(&#x27;/var/run/docker.sock&#x27;)
conn.request(&#x27;GET&#x27;, &#x27;/containers/json?all=1&#x27;)
print(conn.getresponse().read().decode()[:200])
&quot;
</code></pre>
<h2 id="">修复方案</h2><p>将宝塔 Docker 模块中依赖 <code>curl</code> 的 API 调用改为 Python 原生 Socket 方式，绕过 AppArmor 限制。</p><p>需要修改的文件：</p><pre class=""><code class="">/www/server/panel/class/btdockerModel/dockerSock/container.py
</code></pre>
<h3 id="">第一步：备份原文件</h3><pre class="language-bash lang-bash"><code class="language-bash lang-bash">cp /www/server/panel/class/btdockerModel/dockerSock/container.py \
   /www/server/panel/class/btdockerModel/dockerSock/container.py.bak
</code></pre>
<h3 id="">第二步：执行修复脚本</h3><p>将以下内容保存为 <code>/tmp/fix_docker.py</code> 并执行：</p><pre class="language-bash lang-bash"><code class="language-bash lang-bash">cat &gt; /tmp/fix_docker.py &lt;&lt; &#x27;FIXSCRIPT&#x27;
import sys

filepath = &quot;/www/server/panel/class/btdockerModel/dockerSock/container.py&quot;

with open(filepath, &quot;r&quot;) as f:
    content = f.read()

errors = []

# ========== 修复 1：替换 get_container 方法 ==========

old_get_container = &#x27;&#x27;&#x27;    # 2024/3/13 上午 11:20 获取所有容器列表
    def get_container(self):
        \&#x27;\&#x27;\&#x27;
            @name 获取所有容器列表
            @author wzz &lt;2024/3/13 上午 10:54&gt;
            @param &quot;data&quot;:{&quot;参数名&quot;:&quot;&quot;} &lt;数据类型&gt; 参数描述
            @return dict{&quot;status&quot;:True/False,&quot;msg&quot;:&quot;提示信息&quot;}
        \&#x27;\&#x27;\&#x27;
        try:
            return json.loads(public.ExecShell(&quot;curl -s --unix-socket {} http:/{}/containers/json?all=1&quot;.format(self._sock, self.get_api_version()))[0])
        except Exception as e:
            try:
                c_list = public.ExecShell(&quot;whereis curl | awk &#x27;print {$1}&#x27;&quot;)[0].split(&quot; &quot;)
                for c in c_list:
                    if not c.endswith(&quot;/curl&quot;): continue
                    res, err = public.ExecShell(&quot;{} -s --unix-socket {} http:/{}/containers/json?all=1&quot;.format(c, self._sock, self.get_api_version()))
                    if not err: return json.loads(res)
                return []
            except:
                return []&#x27;&#x27;&#x27;

new_get_container = &#x27;&#x27;&#x27;    # 2024/3/13 上午 11:20 获取所有容器列表
    def get_container(self):
        \&#x27;\&#x27;\&#x27;
            @name 获取所有容器列表
            @author wzz &lt;2024/3/13 上午 10:54&gt;
            @param &quot;data&quot;:{&quot;参数名&quot;:&quot;&quot;} &lt;数据类型&gt; 参数描述
            @return dict{&quot;status&quot;:True/False,&quot;msg&quot;:&quot;提示信息&quot;}
        \&#x27;\&#x27;\&#x27;
        try:
            return self._request_docker_api(&quot;/containers/json?all=1&quot;)
        except Exception as e:
            return []

    def _request_docker_api(self, path):
        &quot;&quot;&quot;通过 Python 原生 socket 直接访问 Docker Unix Socket API
        解决 Debian 13 AppArmor 阻止 curl 访问 Unix Socket 的问题&quot;&quot;&quot;
        import http.client
        import socket as _socket
        class UnixHTTPConnection(http.client.HTTPConnection):
            def __init__(self, unix_socket_path):
                super().__init__(&quot;localhost&quot;)
                self._unix_socket_path = unix_socket_path
            def connect(self):
                self.sock = _socket.socket(_socket.AF_UNIX, _socket.SOCK_STREAM)
                self.sock.connect(self._unix_socket_path)
        conn = UnixHTTPConnection(self._sock)
        conn.request(&quot;GET&quot;, path)
        resp = conn.getresponse()
        data = resp.read().decode(&quot;utf-8&quot;)
        conn.close()
        return json.loads(data)&#x27;&#x27;&#x27;

if old_get_container in content:
    content = content.replace(old_get_container, new_get_container)
    print(&quot;[OK] get_container 方法已修复&quot;)
else:
    errors.append(&quot;[ERROR] 未找到 get_container 原始方法，可能已被修改或版本不同&quot;)

# ========== 修复 2：替换 get_container_inspect 方法 ==========

old_inspect = &#x27;&#x27;&#x27;    # 2024/3/28 下午 11:37 获取指定容器的inspect
    def get_container_inspect(self, container_id: str):
        \&#x27;\&#x27;\&#x27;
            @name 获取指定容器的inspect
            @param container_id: 容器id
            @return dict{&quot;status&quot;:True/False,&quot;msg&quot;:&quot;提示信息&quot;}
        \&#x27;\&#x27;\&#x27;
        try:
            return json.loads(public.ExecShell(&quot;curl -s --unix-socket {} http:/{}/containers/{}/json&quot;.format(self._sock, self.get_api_version(), container_id))[0])
        except Exception as e:
            try:
                c_list = public.ExecShell(&quot;whereis curl | awk &#x27;print {$1}&#x27;&quot;)[0].split(&quot; &quot;)
                for c in c_list:
                    if not c.endswith(&quot;/curl&quot;): continue
                    res, err = public.ExecShell(&quot;{} -s --unix-socket {} http:/{}/containers/{}/json&quot;.format(c, self._sock, self.get_api_version(), container_id))
                    if not err: return json.loads(res)
                return []
            except:
                return []&#x27;&#x27;&#x27;

new_inspect = &#x27;&#x27;&#x27;    # 2024/3/28 下午 11:37 获取指定容器的inspect
    def get_container_inspect(self, container_id: str):
        \&#x27;\&#x27;\&#x27;
            @name 获取指定容器的inspect
            @param container_id: 容器id
            @return dict{&quot;status&quot;:True/False,&quot;msg&quot;:&quot;提示信息&quot;}
        \&#x27;\&#x27;\&#x27;
        try:
            return self._request_docker_api(&quot;/containers/{}/json&quot;.format(container_id))
        except Exception as e:
            return []&#x27;&#x27;&#x27;

if old_inspect in content:
    content = content.replace(old_inspect, new_inspect)
    print(&quot;[OK] get_container_inspect 方法已修复&quot;)
else:
    errors.append(&quot;[ERROR] 未找到 get_container_inspect 原始方法，可能已被修改或版本不同&quot;)

# ========== 写入文件 ==========

with open(filepath, &quot;w&quot;) as f:
    f.write(content)

if errors:
    for e in errors:
        print(e)
else:
    print(&quot;\n[SUCCESS] 所有修复已完成！请执行以下命令使修复生效：&quot;)
    print(&quot;  find /www/server/panel/class/btdockerModel -name &#x27;*.pyc&#x27; -delete&quot;)
    print(&quot;  bt restart&quot;)

FIXSCRIPT

/www/server/panel/pyenv/bin/python3 /tmp/fix_docker.py
</code></pre>
<h3 id="">第三步：清理缓存并重启面板</h3><pre class="language-bash lang-bash"><code class="language-bash lang-bash">find /www/server/panel/class/btdockerModel -name &quot;*.pyc&quot; -delete 2&gt;/dev/null
bt restart
</code></pre>
<h3 id="">第四步：验证</h3><p>刷新宝塔面板 Docker 页面，确认容器列表正常显示。</p><h2 id="">注意事项</h2><ol start="1"><li><p><strong>宝塔面板升级可能覆盖修改：</strong> 如果后续升级了宝塔面板，<code>container.py</code> 可能被还原，需要重新执行修复脚本。建议保留 <code>/tmp/fix_docker.py</code> 脚本以备用。</p></li><li><p><strong>其他 Docker 功能如有类似问题：</strong> 如果镜像管理、网络管理、存储卷管理等功能也出现异常，可以检查 <code>/www/server/panel/class/btdockerModel/dockerSock/</code> 目录下的 <code>image.py</code>、<code>network.py</code>、<code>volume.py</code> 等文件，查找类似的 <code>curl --unix-socket</code> 调用，用同样的 <code>_request_docker_api()</code> 方法替换。</p></li><li><p><strong>回滚方法：</strong> 如果需要还原修改：</p></li></ol><pre class="language-bash lang-bash"><code class="language-bash lang-bash">cp /www/server/panel/class/btdockerModel/dockerSock/container.py.bak \
   /www/server/panel/class/btdockerModel/dockerSock/container.py
find /www/server/panel/class/btdockerModel -name &quot;*.pyc&quot; -delete
bt restart
</code></pre>
<h2 id="">修复原理</h2><table><thead><tr><th> 项目 </th><th> 修复前（原始方式） </th><th> 修复后（Python Socket） </th></tr></thead><tbody><tr><td> 通信方式 </td><td> 调用系统 <code>curl</code> 命令 </td><td> Python <code>http.client</code> + <code>socket</code> </td></tr><tr><td> 连接方式 </td><td> <code>curl --unix-socket</code> </td><td> <code>socket.AF_UNIX</code> 直连 </td></tr><tr><td> AppArmor 兼容 </td><td> 被阻止，无法连接 </td><td> 不受限制，正常通信 </td></tr><tr><td> 依赖 </td><td> 依赖外部 curl 命令 </td><td> 仅依赖 Python 标准库 </td></tr></tbody></table></div><p style="text-align:right"><a href="https://dick.plus/posts/default/debian13-bt-docker-fix#comments">览毕，何不一言？</a></p></div>]]></description><link>https://dick.plus/posts/default/debian13-bt-docker-fix</link><guid isPermaLink="true">https://dick.plus/posts/default/debian13-bt-docker-fix</guid><dc:creator><![CDATA[阳子]]></dc:creator><pubDate>Tue, 28 Apr 2026 09:21:45 GMT</pubDate></item></channel></rss>