Docker 是一个开放源代码软件项目,让应用程序布署在软件容器下的工作可以自动化进行,借此在 Linux 操作系统上,提供一个额外的软件抽象层,以及操作系统层虚拟化的自动管理机制。
Docker 利用 Linux 核心中的资源分脱机制,例如 cgroups,以及 Linux 核心名字空间(name space),来创建独立的软件容器(containers)。这可以在单一 Linux 实体下运作,避免启动一个虚拟机造成的额外负担。
简单概括起来就是,Docker 是个容器,什么都能往里塞,你也可以理解为是一个轻量化的虚拟机。
使用 Docker 的好处就是对当前系统的环境没有破坏性,基本上一款镜像可以跑在任意包含了 Docker 的机器上,可以说是十分方便了。
本文主要介绍一下我在学习 Docker 的过程中制作的几款镜像,以及使用方法。
安装并启动 Docker
在以下操作系统里安装最新版 Docker,可以直接运行官方的安装脚本一键安装。
- x86_64-centos-7
- x86_64-fedora-26
- x86_64-fedora-27
- x86_64-fedora-28
- x86_64-debian-wheezy
- x86_64-debian-jessie
- x86_64-debian-stretch
- x86_64-debian-buster
- x86_64-ubuntu-trusty
- x86_64-ubuntu-xenial
- x86_64-ubuntu-bionic
- x86_64-ubuntu-artful
- s390x-ubuntu-xenial
- s390x-ubuntu-bionic
- s390x-ubuntu-artful
- ppc64le-ubuntu-xenial
- ppc64le-ubuntu-bionic
- ppc64le-ubuntu-artful
- aarch64-ubuntu-xenial
- aarch64-ubuntu-bionic
- aarch64-debian-jessie
- aarch64-debian-stretch
- aarch64-debian-buster
- aarch64-fedora-26
- aarch64-fedora-27
- aarch64-fedora-28
- aarch64-centos-7
- armv6l-raspbian-jessie
- armv7l-raspbian-jessie
- armv6l-raspbian-stretch
- armv7l-raspbian-stretch
- armv7l-debian-jessie
- armv7l-debian-stretch
- armv7l-debian-buster
- armv7l-ubuntu-trusty
- armv7l-ubuntu-xenial
- armv7l-ubuntu-bionic
- armv7l-ubuntu-artful
执行脚本方法如下:
- wget -qO- get.docker.com | bash
安装完成后,运行下面的命令,验证是否安装成功。
- docker version
启动 Docker
- systemctl start docker
查看 Docker 启动状态
- systemctl status docker
允许 Docker 开机自启
- systemctl enable docker
Shadowsocks-libev Docker Image
这是我第一款制作出来的 Docker 镜像,基于官方 debian:stretch 镜像制作,在引入 stretch-backports 后,直接利用 apt-get 安装好 shadowsocks-libev simple-obfs 即可。
该容器在启动时依赖于读取宿主机里的配置文件,因此在启动该镜像时配合不同的 config 文件,就能开启任意个 Docker ,也就是所谓的多端口。
把配置文件放在宿主机里,是基于这样的考量:随时在宿主机里修改配置的端口,密码,加密方式等信息,然后只需重启容器,无需再次创建新的容器。
支持的 Tags 及 Dockerfile
3.2.0, latest (Dockerfile)
alpine (Dockerfile)
拉取镜像
- docker pull teddysun/shadowsocks-libev
或者拉取以 alpine 镜像制作的,其特点就是文件容量非常小
- docker pull teddysun/shadowsocks-libev:alpine
创建 config 文件
比如在目录 /etc/shadowsocks-libev 下创建 config.json,完整路径也就是 /etc/shadowsocks-libev/config.json
范例内容如下:
- {
- “server”:“0.0.0.0”,
- “server_port”:9000,
- “password”:“password0”,
- “timeout”:300,
- “method”:“aes-256-gcm”,
- “fast_open”:true,
- “nameserver”:“8.8.8.8”,
- “mode”:“tcp_and_udp”
- }
如果你想同时开启 simple-obfs,那么配置文件范例如下:
- {
- “server”:“0.0.0.0”,
- “server_port”:9000,
- “password”:“password0”,
- “timeout”:300,
- “method”:“aes-256-gcm”,
- “fast_open”:true,
- “nameserver”:“8.8.8.8”,
- “mode”:“tcp_and_udp”,
- “plugin”:“obfs-server”,
- “plugin_opts”:“obfs=tls”
- }
配置文件里面所有选项的含义,可以参考这个链接。
启动容器
在上面这个范例里,定义的端口是 9000,那么在启动容器时就需要将 9000 端口映射到宿主机的对外端口上。
启动命令:
- docker run -d -p 9000:9000 -p 9000:9000/udp –name ss-libev -v /etc/shadowsocks-libev:/etc/shadowsocks-libev teddysun/shadowsocks-libev
docker run:开始运行一个容器。
-d 参数:容器以后台运行并输出容器 ID。
-p 参数:容器的 9000 端口映射到本机的 9000 端口。默认是映射 TCP,当需要映射 UDP 时,那就再追加一次 UDP 的映射。冒号后面是容器端口,冒号前面是宿主机端口,可以写成一致,也可以不一致。
–name 参数:给容器分配一个识别符,方便将来的启动,停止,删除等操作。
-v 参数:挂载卷(volume),冒号后面是容器的路径,冒号前面是宿主机的路径,可以写成一致,也可以不一致。
teddysun/shadowsocks-libev:这是拉取回来的镜像路径。
当然,这里也可以启动 Tag 为 alpine 的镜像命令:
- docker run -d -p 9000:9000 -p 9000:9000/udp –name ss-libev -v /etc/shadowsocks-libev:/etc/shadowsocks-libev teddysun/shadowsocks-libev:alpine
注意:此处仅作为演示,不能同时执行上面的这两个启动命令,因为端口都是 9000,产生冲突了。一般我是推荐选 Tag 为 alpine 的镜像的,因为文件的体积会相对比较小。
查看容器
利用如下命令可以查看所有已创建的 Docker 容器并显示容器的大小等信息:
- docker ps -as
停止容器
利用如下命令可以停止正在运行中的容器:
- docker stop $name
此处的 $name 就是在启动容器那一步定义的容器的识别符,比如范例的 ss-libev
启动容器
利用如下命令可以停止正在运行中的容器:
- docker start $name
此处的 $name 就是在启动容器那一步定义的容器的识别符,比如范例的 ss-libev
ShadowsocksR Docker Image
这是我第二款制作出来的 Docker 镜像,基于官方 debian:stretch 镜像制作,安装的是 Github 上目前最新的版本。
该容器在启动时依赖于读取宿主机里的配置文件,因此在启动该镜像时配合不同的 config 文件,就能开启任意个 Docker ,也就是所谓的多端口。
把配置文件放在宿主机里,是基于这样的考量:随时在宿主机里修改配置的端口,密码,加密方式等信息,然后只需重启容器,无需再次创建新的容器。
支持的 Tags 及 Dockerfile
3.2.2, latest (Dockerfile)
alpine (Dockerfile)
拉取镜像
- docker pull teddysun/shadowsocks-r
或者拉取基于 python:3.6-alpine 镜像制作的
- docker pull teddysun/shadowsocks-r:alpine
创建 config 文件
比如在目录 /etc/shadowsocks-r 下创建 config.json,完整路径也就是 /etc/shadowsocks-r/config.json
范例内容如下:
- {
- “server”:“0.0.0.0”,
- “server_ipv6”:“::”,
- “server_port”:9000,
- “local_address”:“127.0.0.1”,
- “local_port”:1080,
- “password”:“password0”,
- “timeout”:120,
- “method”:“aes-256-cfb”,
- “protocol”:“origin”,
- “protocol_param”:“”,
- “obfs”:“plain”,
- “obfs_param”:“”,
- “redirect”:“”,
- “dns_ipv6”:false,
- “fast_open”:true,
- “workers”:1
- }
ShadowsocksR 协议插件文档的含义,可以参考这个链接。
启动容器
在上面这个范例里,定义的端口是 9000,那么在启动容器时就需要将 9000 端口映射到宿主机的对外端口上。
启动命令:
- docker run -d -p 9000:9000 -p 9000:9000/udp –name ssr -v /etc/shadowsocks-r:/etc/shadowsocks-r teddysun/shadowsocks-r
启动 Tag 为 alpine 的镜像命令:
- docker run -d -p 9000:9000 -p 9000:9000/udp –name ssr -v /etc/shadowsocks-r:/etc/shadowsocks-r teddysun/shadowsocks-r:alpine
注意:此处仅作为演示,不能同时执行上面的这两个启动命令,因为端口都是 9000,产生冲突了。一般我是推荐选 Tag 为 alpine 的镜像的,因为文件的体积会相对比较小。
L2TP/IPsec VPN Server Docker Image
这是我第三款制作出来的 Docker 镜像,基于官方 debian:stretch 镜像制作,使用了最新版 libreswan-3.25 和 xl2tpd-1.3.12,支持 L2TP/IPsec PSK 和 IPSec Xauth PSK 两种连接方式。
需要注意的是,Android 版本小于等于 7.0 时,建议选择 IPSec Xauth PSK 模式连接,否则可能会连接失败。如下图所示:
该镜像在启动之前,需事先定义环境变量文件 /etc/l2tp.env,其内容具体参考以下的说明。
同时,该镜像具备自主管理用户的特点,一个简单命令即可增删改查用户账号。
支持的 Tags 及 Dockerfile
latest (Dockerfile)
拉取镜像
- docker pull teddysun/l2tp
创建启动环境参数文件
比如是 /etc/l2tp.env,该文件内的各个变量定义如下:
- VPN_IPSEC_PSK=teddysun.com
- VPN_USER=vpnuser
- VPN_PASSWORD=vpnpassword
- VPN_PUBLIC_IP=
- VPN_L2TP_NET=
- VPN_L2TP_LOCAL=
- VPN_L2TP_REMOTE=
- VPN_XAUTH_NET=
- VPN_XAUTH_REMOTE=
- VPN_DNS1=
- VPN_DNS2=
VPN_IPSEC_PSK:预共享密钥
VPN_USER:默认的登录用户名
VPN_PASSWORD:默认的登录用户密码
VPN_PUBLIC_IP:指定公网 IP 地址,当你的 VPS 有多个公网 IP 时,可能需要手动指定一下
VPN_L2TP_NET:内网 L2TP 网段范围,默认为 192.168.18.0/24,一般此处留空即可
VPN_L2TP_LOCAL:内网 L2TP 网关 IP,默认为 192.168.18.1,一般此处留空即可
VPN_L2TP_REMOTE:内网 L2TP 网段分配给连接的 IP 段,默认为 192.168.18.10-192.168.18.250,一般此处留空即可
VPN_XAUTH_NET:内网 XAUTH 网段范围,默认为 192.168.20.0/24,一般此处留空即可
VPN_XAUTH_REMOTE:内网 XAUTH 网段分配给连接的 IP 段,默认为 192.168.20.10-192.168.20.250,一般此处留空即可
VPN_DNS1:默认 DNS 服务器,8.8.8.8,一般此处留空即可
VPN_DNS2:默认 DNS 服务器,8.8.4.4,一般此处留空即可
启动容器
在这个范例里,需要将 500 和 4500 端口的 UDP 映射到宿主机的对外端口上。
启动命令:
- docker run -d –privileged -p 500:500/udp -p 4500:4500/udp –name l2tp –env-file /etc/l2tp.env -v /lib/modules:/lib/modules teddysun/l2tp
查看启动日志
- docker logs l2tp
此处的 l2tp,是指在启动时定义的容器识别符,–name 参数后的名字。
输出的日志参考如下:
- L2TP/IPsec VPN Server with the Username and Password is below:
- Server IP: Your Server public IP
- IPSec PSK: IPSec PSK (pre-shared key)
- Username : VPN username
- Password : VPN password
- Redirecting to: /etc/init.d/ipsec start
- Starting pluto IKE daemon for IPsec: Initializing NSS database
- xl2tpd[1]: Not looking for kernel SAref support.
- xl2tpd[1]: Using l2tp kernel support.
- xl2tpd[1]: xl2tpd version xl2tpd-1.3.12 started on 1d20eaecd9f2 PID:1
- xl2tpd[1]: Written by Mark Spencer, Copyright (C) 1998, Adtran, Inc.
- xl2tpd[1]: Forked by Scott Balmos and David Stipp, (C) 2001
- xl2tpd[1]: Inherited by Jeff McAdams, (C) 2002
- xl2tpd[1]: Forked again by Xelerance (www.xelerance.com) (C) 2006–2016
- xl2tpd[1]: Listening on IP address 0.0.0.0, port 1701
当然,你也可以查看一下 ipsec status 命令的输出,命令如下:
- docker exec -it l2tp ipsec status
此处的 l2tp,是指在启动时定义的容器识别符,–name 参数后的名字。
管理 VPN 用户
列出全部用户及其密码
- docker exec -it l2tp l2tpctl -l
新增一个用户
- docker exec -it l2tp l2tpctl -a
删除一个用户
- docker exec -it l2tp l2tpctl -d
修改一个用户的密码
- docker exec -it l2tp l2tpctl -m
打印控制脚本 l2tpctl 的帮助信息
- docker exec -it l2tp l2tpctl -h
需要注意的是,容器一旦被删除重建,或者停止后重新启动,都会导致 VPN 用户信息的丢失,需要通过以上的命令再次创建。
Windows 10 下连接 L2TP VPN
首先,参考下图的设置,将 VPN 的连接信息稍微修改一下。
修改 VPN 属性,如图所示。
一般我们都是连接到家用路由器上的,也就是说,我们的网络一般都是处于 NAT 状态下,因此还需要改一下注册表,根据这个链接,修改注册表的信息,修改完成后,重启 Windows 即可。