podman

和 docker 的使用方法基本一致,不需要 daemon,且普通用户可使用。

https://docs.podman.io/en/latest/Commands.html

Debian 安装后可以直接用,Alpine 下面依赖 cgroups 和 crun :

apk add crun
service cgroups start
# 或者开机启动: rc-update add cgroups

顺便在这里提一句 Alpine 的安装完成后,apk list -I | grep linux-firmware, 一般,只需要保留 other 和 有线网卡的包。 蓝牙、显卡、声音什么的都可以卸载掉,比如 intel 的显卡驱动还有拔掉显示器就死机的坑。

Alpine 安装时可以利用 answer file,可以指定禁用 swap。

宿主机追求简单,建议用 Alpine Linux,然后在上面跑最新的 debian 来工作,比如我的:

# 容器名 q
# 容器内 hostname 为 q
# 使用宿主的网络、shm 等资源,方便交互
# 挂载本地重要数据目录
# 容器内 /tmp 使用内存
podman run -it -d \
--name q \
--net host \
--ipc host \
--hostname q \
-v ./etc:/etc \
-v ./usr:/usr \
-v ./var:/var \
-v ./run:/run \
-v ./root:/root \
--tmpfs /tmp \
docker.io/lwzm/sshd:debian

启用镜像默认前缀,启用镜像加速:

/etc/containers/registries.conf

unqualified-search-registries = ["docker.io"]
[[registry]]
prefix = "docker.io"
location = "lwzm-docker-registry.pages.dev"
#location = "lwdakpha.mirror.aliyuncs.com"
# https://cr.console.aliyun.com/cn-shanghai/instances/mirrors

容器内的 /etc/hosts 会跟随宿主机的,且宿主机的 IP 是可以从容器内直连,宿主可以识别到容器的真实 IP。

如果外部想访问容器的 IP,可以把宿主当网关。如 ip route add 10.88.0.0/16 via 10.0.0.243

如宿主的 hosts 含 10.0.0.10 foo,启动 python3 -m http.server,则容器内 curl foo:8000 可访问到宿主机,且宿主机可发现访问者的 IP。

例子:

podman run --name ss -e PASSWORD=x*** -e METHOD=aes-256-gcm -p 127.1.1.1:58388:8388 -d shadowsocks/shadowsocks-libev
#
# ...
podman container start ss

nginx 做网关:

先创建个网络方便互通 podman network create q ,然后

podman run \
-v /etc/localtime:/etc/localtime:ro \
-v ./conf.d:/etc/nginx/conf.d \
-v ./.lego/certificates:/certificates \
-v ./log:/var/log/nginx \
-v ./html:/html \
-p 80:80 \
-p 443:443 \
--network q \
--name nginx \
nginx:alpine

# podman start nginx

注意如果是普通用户,需要绑定小数字端口,可以 root 先跑 echo 80 >/proc/sys/net/ipv4/ip_unprivileged_port_start

接下来,创建 container 或 pod 或 kube,指定 --network q 就行了。

nginx 有几个问题:获取不了真实的访问者 IP、无法及时发现上游 IP 的变更,可以中间加个 caddy 解决,这时,nginx 不用容器跑。

./caddy/Caddyfile:

http://adminer.*.* {
        reverse_proxy adminer:8080
}

http://whoami.*.* {
        reverse_proxy {
                to whoami-pod-0
                to whoami-pod-1
        }
}

:80 {
        reverse_proxy {
                to {labels.2}:80
        }
}

caddy 用容器跑:

podman run -d --network q \
-v ./caddy:/etc/caddy \
--name caddy \
-p 127.255.255.254:58888:80 \
caddy

nginx:

server {
        listen 80 default_server;
        return 301 https://$host$request_uri;
}

server {
        listen 443 ssl http2 default_server;

        if ( $host !~ ^(.+)\.tyio\.net$ ) {
                return 403;
        }

        root /html/$1;

        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
}

server {
    server_name tyio.net;
        root /html/www;
}

upstream caddy {
    server 127.255.255.254:58888;
    keepalive 64;
}

server {
    server_name
        adminer.tyio.net
        whoami.tyio.net
        ...
        ;
        listen 443 ssl http2;

    location / {
                proxy_pass http://caddy;
    }
}