容器重建后浏览器登录态不丢失的挂载与改写方案
现象:profile 挂载对了,重启后仍要重新登录
容器里跑浏览器做采集或自动化,第一步通常是把 --user-data-dir 指到宿主机挂载的卷上,以为登录态就此保住。结果 docker restart 之后打开页面,还是登录页;书签、历史、密码都在,唯独登录态没了。
问题不在挂载,在 cookie 本身。绝大多数站点的会话 cookie 不带 Expires 或 Max-Age,浏览器把它标记为 session cookie,只活在进程生命周期里。更麻烦的是 Chrome 退出时会用内存状态回写数据库,你在它运行期间改的过期时间,会被原样覆盖回去。
先确认 Cookie 文件到底在哪
Chrome 96 之后 cookie 库从 Default/Cookies 挪到了 Default/Network/Cookies。用旧路径会改到一个不再被读取的文件,脚本退出码是 0,但一点效果没有。进容器看一眼:
ls -l /profile/Default/Network/Cookies /profile/Default/Cookies
它是标准 SQLite,cookies 表里跟持久化相关的是三列:is_persistent、has_expires、expires_utc。session cookie 的特征就是这三列全为 0。
一条 SQL 把 session cookie 批量改成持久 cookie
expires_utc 不是 Unix 时间戳,是「1601-01-01 起的微秒数」,Chrome 全系沿用这个基准,和 Unix 纪元差 11644473600 秒。下面这条把目标域名的 session cookie 统一改成 30 天后过期:
UPDATE cookies SET is_persistent=1, has_expires=1, expires_utc=(CAST(strftime('%s','now') AS INTEGER)+11644473600+2592000)*1000000 WHERE is_persistent=0 AND host_key LIKE '%example.com';
2592000 是 30 天,改成 7 天用 604800。WHERE 里的域名条件别省,否则整个 profile 里所有站点的 cookie 都被拉长有效期,出问题很难查。
entrypoint 里的执行顺序才是关键
这条 SQL 必须在浏览器进程启动之前、在同一个 entrypoint 里串行执行。两种常见错法:
- 用
docker exec进已经跑起来的容器改库。Chrome 早把数据读进内存了,你改的是磁盘副本,它退出时照样覆盖回去。 - 后台起一个 sidecar 去改,和 Chrome 抢同一个 SQLite 文件,轻则语句拿不到锁失败,重则把库写坏。
entrypoint.sh 按这个顺序写:
#!/bin/shset -eDB=/profile/Default/Network/Cookies[ -f "$DB" ] && sqlite3 "$DB" "UPDATE cookies SET is_persistent=1, has_expires=1, expires_utc=(CAST(strftime('%s','now') AS INTEGER)+11644473600+2592000)*1000000 WHERE is_persistent=0 AND host_key LIKE '%example.com';"rm -f /profile/SingletonLock /profile/SingletonSocket /profile/SingletonCookieexec google-chrome --user-data-dir=/profile --remote-debugging-port=9222
第五行的 rm -f 不能漏。容器每次重建 hostname 都不一样,profile 里残留的 SingletonLock 指向一个已经不存在的 hostname,Chrome 会认为有另一个实例正在使用这个 profile,弹出 profile appears to be in use 并拒绝启动。
容器重建后怎么验证登录态还在
- 重建:
docker rm -f chrome && docker run -d --name chrome -v /srv/chrome-profile:/profile browser:1.0 - 查落盘结果:
docker run --rm --entrypoint sqlite3 -v /srv/chrome-profile:/profile browser:1.0 /profile/Default/Network/Cookies "SELECT name, is_persistent, datetime(expires_utc/1000000-11644473600,'unixepoch') FROM cookies WHERE host_key LIKE '%example.com';"用--entrypoint另起一个容器读,避免和正在跑的 Chrome 抢文件。 - 看登录态:新容器起来后打开页面,能直接进已登录状态、不跳登录页,才算通过。
还不通过的话,先查 expires_utc 是不是仍为 0(说明 SQL 没命中,多半是 host_key 写错),再确认读的是不是 Default/Network/Cookies 这个路径。
两个容易忽略的坑
- cookie 值是加密的。
value列通常为空,真实内容在encrypted_value里,Linux 下由 keyring 或回退口令派生的密钥加密。换基础镜像、换 keyring 策略后旧 cookie 解不开,表现为记录都在但站点依然要求登录,只能重新登录一次再跑一遍改写。 - 别用
docker commit固化登录态。cookie 会过期,站点也会因为 UA、IP 变化主动失效,profile 卷加上这条 SQL 才是可重复的做法。
- 点赞
- 收藏
- 关注作者
评论(0)