LXC 3.0

DebianをBusterにアプグレードして、その際、LXCもバージョンが3.0となりました。ところが仕様がかなり変わったので非特権ユーザーがアクセスできないという事態になりました。教訓として特権ユーザーでコンテナを作ることとアクセスする手段を複数用意することです。lxc-attachに頼りすぎたためにアクセスできなくなってしまったのですがsshサーバは各コンテナで起動しておいたほうが良でしょう。

今まではlibvirtでLXCネットワークを作っていましたが、今はVLANとブリッジになっているようです。LXCコンテナを最新の仕様に合わせて作り直しました。ネットワークの設定はいくつかあるのですが旧来のやり方がシンプルで問題がありません。

/etc/network/interfaces

source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
iface eth0 inet static
	address ${VPS IP}
	netmask 255.255.255.0
	network ${VPS NETWORK}
	broadcast ${VPS BROADCAST}
	gateway ${VPS GATEWAY}
	# dns-* options are implemented by the resolvconf package, if installed
	dns-nameservers 121.83.238.17
	dns-search vps.ablenet.jp

iface eth0.111 inet manual

auto br0
iface br0 inet static
  bridge_ports eth0.111 
  address 10.0.0.1
  netmask 255.255.255.0
  broadcast 10.0.0.255
  network 10.0.0.0
  gateway 10.0.0.1
  bridge_maxwait 0
  bridge_fd 0
  #bridge_hello 2
  #bridge_maxage 12
  bridge_stp off

/etc/lxc/default.conf

lxc.net.0.type = veth
lxc.net.0.link = virbr0
lxc.net.0.flags = up
lxc.apparmor.profile = generated
lxc.apparmor.allow_nesting = 1

/etc/lxc/lxc-usernet

root	veth	lxcbr0	24

/var/lib/lxc/debian/config

lxc.start.auto = 0
lxc.group = group00

# Distribution configuration
lxc.include = /usr/share/lxc/config/common.conf
lxc.arch = linux64

# Container specific configuration
lxc.apparmor.profile = generated
lxc.apparmor.allow_nesting = 1
lxc.rootfs.path = dir:/var/lib/lxc/debian/rootfs
lxc.uts.name = debian-base

# Network configuration
lxc.net.0.type = veth
lxc.net.0.link = br0
lxc.net.0.flags = up
lxc.net.0.veth.pair = vethvm01

 

スナップショット

/var/lib/lxc/openvpn/config

lxc.start.auto = 0
lxc.group = group01

# Distribution configuration
lxc.include = /usr/share/lxc/config/common.conf
lxc.arch = linux64

# Container specific configuration
lxc.apparmor.profile = generated
lxc.apparmor.allow_nesting = 1
lxc.rootfs.path = overlay:/var/lib/lxc/debian/rootfs:/var/lib/lxc/openvpn/delta0
lxc.uts.name = openvpn

# Network configuration
lxc.net.0.type = veth
lxc.net.0.link = br0
lxc.net.0.flags = up

# tun/tap configuration
#lxc.cgroup.devices.deny = a
lxc.hook.autodev = sh -c "modprobe tun"
lxc.cgroup.devices.allow = c 10:200 rwm
lxc.mount.entry=/dev/net/tun /var/lib/lxc/openvpn/rootfs/dev/net/tun none bind,create=file

/etc/default/lxc

# LXC_AUTO - whether or not to start containers at boot
LXC_AUTO="true"
BOOTGROUPS="onboot,group02,group01"
SHUTDOWNDELAY=5
OPTIONS=
STOPOPTS="-a -A -s"
USE_LXC_BRIDGE="false"  # overridden in lxc-net
[ ! -f /etc/default/lxc-net ] || . /etc/default/lxc-net

稼働状況をみる

lxc-ls -f
NAME            STATE   AUTOSTART GROUPS  IPV4                    IPV6 UNPRIVILEGED 
debian          STOPPED 0         group00 -                       -    false        
srv08_radius    RUNNING 1         group02 10.0.0.8                -    false        
srv05_mariadb   RUNNING 1         group02 10.0.0.5                -    false        
srv02_http      RUNNING 1         group02 10.0.0.2                -    false        
srv03_mail      RUNNING 1         group02 10.0.0.3                -    false        
srv11_tinc      RUNNING 1         group02 10.0.4.251, 10.0.0.11   -    false        
srv10_test      STOPPED 0         group00 -                       -    false        
openvpn         RUNNING 0         group01 10.0.0.200, 10.8.0.14   -    false

IPv6を使わない場合

/etc/sysctl.conf

net.ipv6.conf.all.disable_ipv6 = 1

追記:ダウンロードのときエラーが出る場合。リスクと引き換えにセキュリティチェックを外せばダウンロードできます。

エラー表示:

lxc-create --name debian-tmp -t download
Setting up the GPG keyring
ERROR: Unable to fetch GPG key from keyserver
lxc-create: debian-tmp: lxccontainer.c: create_run_template: 1617 Failed to create container from template
lxc-create: debian-tmp: tools/lxc_create.c: main: 327 Failed to create container debian-tmp

/usr/share/lxc/templates/lxc-download

DOWNLOAD_VALIDATE="false"

LXC or LXD?

DebianにはLXDがないのですがsnapでインストールできます。しかしアンインストールすると全てコンテナを消し去ってしまうので注意が必要です。

問題はコンテナをExport/Importする場合です。コンテナを使いまわしをして時間を節約することはコンテナを使う理由の一つです。(追記:Debianー>UbuntuはAppArmor周りの不具合があります。同じディストリビューション及びバージョンでなければ動作の保障はありません)

LXDならlxcコマンドでできるのですがLXCには対応するコマンドがありません。

しかしコンテナイメージをtar.gz化して/var/lib/lxc配下に展開すればとくに問題なく移植が可能なようです。

Tinc VPNの設定

2つのVPS間を結ぶVPNでIKEv2が使えないとなると一般的にはOpenVPNになりますが、今回2点間を繋ぐだけなのでシンプルなTinc VPNを使ってみました。実はTincは自宅のメッシュネットワークに乗せて使っていて1年以上使っていますが、普通のLANケーブルと同じくらいスムーズな接続ができています。この実績から今回、TincでVPS間を結んでみようということになりました。

Tincはメッシュ型VPNでクライアント・サーバ型ではないのでルーティングの設定がすこし複雑になります。設定方法は検索でもヒットするしTincのホームページにもあるので、それを参照します。

Client(moon)側

まず/etc/tinc上に作りたいVPN名のディレクトリを作ります。

例)

mkdir /etc/tinc/mynet

つぎにディレクトリに移動してつぎの3つのファイルを作ります。

cd /etc/tinc/mynet

例)tinc.conf

Name = moon
AddressFamily = ipv4
Interface = tinc0
Mode = router
ConnectTo = sun

例)tinc-up

#!/bin/sh

VPN_HOST=10.0.0.2
ip link set $INTERFACE up
ip addr add ${VPN_HOST}/24 dev $INTERFACE

tinc-down

#!/bin/sh

VPN_HOST=10.0.0.2
ip addr del ${VPN_HOST}/24 dev $INTERFACE
ip link set $INTERFACE down

実行パーミッションをつけます。

chmod +x tinc-*

次にhostsディレクトリを作ります。

mkdir -p /etc/tinc/mynet/hosts

秘密鍵を作ります。

tincd -n mynet -K4096

そうするとhostsディレクトリにClient名の公開鍵ができます。そのファイルを編集します。AddressはパグリックIPを割り当てます。同様にサーバ側も同じようにします。そして相互にhostsの中に公開鍵のファイルを入れます。

例)hosts/moon

Compression = 9
Address = 1.2.3.4
Port = 655
Subnet = 10.0.0.2/32
-----BEGIN RSA PUBLIC KEY-----

-----END RSA PUBLIC KEY-----

firewallでインターネットにアクセスできようにしてテストしてみます。

tincd -c /etc/tinc/mynet -d3

syslogをみて不具合がないかチェックします。なければ先に進めます。

接続できたらルーティングを設定します。

例)tinc-up

#!/bin/sh

ORIGINAL_GATEWAY=`ip route show | grep ^default | cut -d ' ' -f 2-5`
REMOTE_IP=6.7.8.9
VPN_GATEWAY=10.0.0.1
VPN_HOST=10.0.0.2

ip link set $INTERFACE up
ip addr add ${VPN_HOST}/24 dev $INTERFACE
ip route add $REMOTE_IP $ORIGINAL_GATEWAY
ip route add $VPN_GATEWAY dev $INTERFACE
ip route add 0.0.0.0/1 via $VPN_GATEWAY dev $INTERFACE
ip route add 128.0.0.0/1 via $VPN_GATEWAY dev $INTERFACE
ip route add 192.168.1.0/24 via 192.168.1.1 dev eth0  # 192.168.1.0/24はClient側のネットワークです
#ip route add 10.10.0.0/24 via 192.168.1.1 dev eth0

例)tinc-down

ORIGINAL_GATEWAY=`ip route show | grep ^default | cut -d ' ' -f 2-5`
REMOTE_IP=6.7.8.9
VPN_GATEWAY=10.0.0.1
VPN_HOST=10.0.0.2

ip route del $REMOTE_IP $ORIGINAL_GATEWAY
ip route del $VPN_GATEWAY dev $INTERFACE
ip route del 0.0.0.0/1 dev $INTERFACE
ip route del 128.0.0.0/1 dev $INTERFACE
ip route del 192.168.1.0/24 via 192.168.1.1 dev eth0
ip addr del ${VPN_HOST}/24 dev $INTERFACE
ip link set $INTERFACE down

 

Server(moon)側

サーバ(sun)側の設定をします。Subnet = 0.0.0.0/0とします。

例)/etc/tinc/mynet/hosts/sun

#Compression = 9
Address = 6.7.8.9
Port = 655
#Subnet = 10.0.0.1/32
Subnet = 0.0.0.0/0

-----BEGIN RSA PUBLIC KEY-----

-----END RSA PUBLIC KEY-----

例)tinc.conf

Name = sun
#Device = /dev/net/tun
AddressFamily = ipv4
Interface = tinc0
Mode = router
ConnectTo = moon

例)tinc-up

#!/bin/sh

ip link set $INTERFACE up
ip addr add 10.0.0.1/24 dev $INTERFACE

例)tinc-down

#!/bin/sh

ip addr del 10.0.4.241/28 dev $INTERFACE
ip link set $INTERFACE down

SNATを使ってアドレス変換をします。そして相互に立ち上げなおしてテストしてみます。

tracepath bbc.com
 1?: [LOCALHOST]                      pmtu 1500
 1:  151.101.128.81                                        0.111ms pmtu 1394
 1:  10.0.4.241                                           74.201ms 
 2:  sgssdsemi2.a2hosting.com                             73.598ms asymm  1 
 3:  be2-60.br04.sin02.pccwbtn.net                        74.286ms 
 4:  hundredge0-6-0-2.br02.hkg12.pccwbtn.net             107.420ms asymm  5 
 5:  hundredge0-6-0-2.br02.hkg12.pccwbtn.net             106.839ms 
 6:  no reply
1:151.101.128.81(California (CA) (60% confidence), United States (US) (99% confidence)
1: 10.0.4.241(TINC VPN server)
2: sgssdsemi2.a2hosting.com :103.227.177.5 (Singapore)

IPを調べるとパケットがアメリカからシンガポールに飛んでるようです。ですが 0.111msなので大阪のデータセンタからそんな短時間では到達できないので恐らくフェイクでしょう。でシンガポールリージョンまで75ms以下だから大体あっているでしょう。ちなみに日本からワシントン・ポスト紙まで223.924msで1/3程度なのでレイテンシーがだいたい距離に比例していると推察できます。

ともかく、すべてが問題なければsystemdに登録します。

sudo systemctl enable tinc@mynet
sudo systemctl start tinc

以上で設定は終わりです。

追記:Client側のfirewallの設定(参考)

ufw default deny outgoing
ufw default deny incoming
ufw allow in on eth0 from any port 22 proto tcp
#ufw allow ssh
ufw allow out on eth0 to 192.168.1.5/32 port 3306 proto tcp
ufw allow 655
ufw allow out 655
ufw allow out on tinc0 from any to any
ufw allow in on tinc0 from any to any
ufw allow in from 6.7.8.9/32
ufw allow out from 6.7.8.9/32
ufw allow from 10.0.4.0/24
ufw allow out from 10.0.4.0/24
ufw allow from 192.168.1.0/24
ufw allow in from 192.168.200.128/27