LoginSignup
3
5

More than 5 years have passed since last update.

[CentOS 7]systemd-nspawnでテスト環境をつくってみた

Last updated at Posted at 2017-06-25

概要

CentOS7のホストの上にsystemd-nspawnでシステムコンテナを立てる方法の備忘録です

元となるマスターコンテナ(テンプレート)と
それのクローンコンテナを作ります

(以下のコマンドはroot/sudoで実行しています)

環境

CentOS-7-x86_64-Minimal-1611.isoから
minimal installのちyum updateを実行(2017/06/25)

前提

以下のものを使用するのでインストールします

  • systemd-networkd
  • systemd-resolved
  • screen
  • perl
  • policycoreutils-python
ホスト側
yum install \
 systemd-networkd \
 systemd-resolved \
 policycoreutils-python \
 screen \
 perl \
 -y

環境や設定は以下のものを使うので適宜読み替えてください

#インターネット接続されたデバイス名、DHCP有効
EXTERNAL_DEV_NAME='enp0s3'
#↑のデバイスが属するzone
EXTERNAL_ZONE_NAME='public'

#仮想ブリッジデバイス名
INTERNAL_DEV_NAME='br0'
#仮想ブリッジデバイス、コンテナが属するzone
INTERNAL_ZONE_NAME='internal'
#仮想ブリッジデバイスのIPアドレス設定
INTERNAL_GATEWAY_ADDR='10.0.0.1'
INTERNAL_NETWORK_PREFIX='24'

#コンテナが使用するDNSサーバーのアドレス
DNS_ADDR='8.8.8.8'

マスターコンテナの設定

#初回ログイン時のrootパスワード
CONTAINERS_MASTER_FIRST_ROOT_PASSWD='password'
#コンテナのデータを置くディレクトリ
CONTAINERS_MASTER_DATA_DIR='/root/data/containers/master/'
#コンテナのIPアドレス
CONTAINERS_MASTER_NETWORK_ADDR='10.0.0.2'

クローンコンテナの設定

#クローン元のコンテナのデータがあるディレクトリ
CONTAINERS_MASTER_DATA_DIR='/root/data/containers/master/'
#クローンコンテナのデータを置くディレクトリの親
CONTAINERS_CLONE_DATA_DIR='./data/containers/clones/'

#コンテナ名
L_CONTAINER_NAME='serv1'
#初回ログイン時のrootパスワード
CONTAINERS_CLONE_FIRST_ROOT_PASSWD='pass1'
#コンテナのIPアドレス
CONTAINERS_CLONE_NETWORK_ADDR='10.0.0.11'

ホストのネットワーク設定

systemd-networkdを利用するように変更

ホスト側
systemctl stop NetworkManager
systemctl disable NetworkManager

systemctl start systemd-networkd systemd-resolved
systemctl enable systemd-networkd systemd-resolved

#systemd-resolvedは直接/etc/resolv.confを変更しないので
mv /etc/resolv.conf /etc/resolv.conf.orig
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf

#systemd-networkd用の設定ファイル
mkdir -p /etc/systemd/network/

cat << EOS > /etc/systemd/network/${EXTERNAL_DEV_NAME}.network
[Match]
Name=${EXTERNAL_DEV_NAME}
[Network]
DHCP=yes
EOS

chmod 644 /etc/systemd/network/${EXTERNAL_DEV_NAME}.network

コンテナ用のプライベートネットワークを作成

コンテナとホストを接続するブリッジデバイスを作成

ホスト側
cat << EOS > /etc/systemd/network/${INTERNAL_DEV_NAME}.netdev
[Match]
[NetDev]
Name=${INTERNAL_DEV_NAME}
Kind=bridge
EOS
chmod 644 /etc/systemd/network/${INTERNAL_DEV_NAME}.netdev

cat << EOS > /etc/systemd/network/${INTERNAL_DEV_NAME}.network
[Match]
Name=${INTERNAL_DEV_NAME}
[Network]
Address=${INTERNAL_GATEWAY_ADDR}/${INTERNAL_NETWORK_PREFIX}
IPForward=yes
EOS
chmod 644 /etc/systemd/network/${INTERNAL_DEV_NAME}.network

コンテナからのインターネットアクセスをホスト経由で行えるように設定

/etc/systemd/network/${EXTERNAL_DEV_NAME}.network
#[Network]セクションに追加
IPForward=kernel
IPMasquerade=yes

以上の設定を読み込み、IPマスカレードできるよう設定

ホスト側
systemctl restart systemd-networkd

firewall-cmd --permanent --zone=${INTERNAL_ZONE_NAME} --change-interface=${INTERNAL_DEV_NAME}
firewall-cmd --permanent --zone=${EXTERNAL_ZONE_NAME} --change-interface=${EXTERNAL_DEV_NAME}
firewall-cmd --permanent --zone=${EXTERNAL_ZONE_NAME} --add-masquerade
firewall-cmd --reload

マスターコンテナ作成

コンテナのデータを置くディレクトリを作成し、絶対パスを取得
(コンテナ内のルートディレクトリ)

ホスト側
mkdir -p ${CONTAINERS_MASTER_DATA_DIR}
L_CONTAINER_ROOT_DIR=$(readlink -f ${CONTAINERS_MASTER_DATA_DIR})

コンテナ内に必要なものをインストール
コンテナ内にカーネルは必要ないので--exclude=kernel*

ホスト側
yum --installroot=${L_CONTAINER_ROOT_DIR} \
 --releasever=7 --disablerepo='*' --enablerepo=base \
 group install 'core' 'base' \
 --exclude=kernel* \
 -y

yum --installroot=${L_CONTAINER_ROOT_DIR} \
 --releasever=7 --disablerepo='*' --enablerepo=base \
 install 'systemd-networkd' \
 --exclude=kernel* \
 -y

echo exclude=kernel* >> ${L_CONTAINER_ROOT_DIR}/etc/yum.conf

初期パスワードを設定

ホスト側
sed -i \
 -e "s@^root:[^:]*@root:$(perl -E "say crypt('"${CONTAINERS_MASTER_FIRST_ROOT_PASSWD}"', '\$6\$'. crypt(rand, rand 100))")@" \
 ${L_CONTAINER_ROOT_DIR}/etc/shadow

コンテナのネットワーク設定

ホスト側
systemctl disable NetworkManager --root=${L_CONTAINER_ROOT_DIR}
systemctl enable systemd-networkd --root=${L_CONTAINER_ROOT_DIR}

cat << EOS > ${L_CONTAINER_ROOT_DIR}/etc/resolv.conf
nameserver ${DNS_ADDR}
EOS

mkdir -p ${L_CONTAINER_ROOT_DIR}/etc/systemd/network/
cat << EOS > ${L_CONTAINER_ROOT_DIR}/etc/systemd/network/host0.network
[Match]
Name=host0
[Network]
Address=${CONTAINERS_MASTER_NETWORK_ADDR}/${INTERNAL_NETWORK_PREFIX}
Gateway=${INTERNAL_GATEWAY_ADDR}
EOS

touch ${L_CONTAINER_ROOT_DIR}/etc/sysconfig/network

コンテナのセキュリティコンテキストを初期化

ホスト側
restorecon -Rv ${L_CONTAINER_ROOT_DIR}

コンテナを起動します

ホスト側
screen -S 'master' systemd-nspawn -b -D ${L_CONTAINER_ROOT_DIR} --network-bridge=${INTERNAL_DEV_NAME}

コンテナのログインプロンプトが表示されるのでroot/初期パスワードでログインし、自由に環境を構築して下さい

備考

コンソールから抜ける場合

以下の順にキーを押す
Ctrl+a
d

コンソールに再度入る場合

ホスト側
screen -r 'master'

クローンコンテナの作成

(マスターコンテナはシャットダウンして下さい)

コンテナのデータを置くディレクトリを作成し、絶対パスを取得

ホスト側
L_CONTAINER_ROOT_DIR=${CONTAINERS_CLONE_DATA_DIR}/${L_CONTAINER_NAME}
mkdir -p ${L_CONTAINER_ROOT_DIR}
L_CONTAINER_ROOT_DIR=$(readlink -f ${L_CONTAINER_ROOT_DIR})

マスターコンテナのデータディレクトリにオーバーレイしたディレクトリを作成
(コンテナ内のルートディレクトリ)

ホスト側
mkdir -p ${L_CONTAINER_ROOT_DIR}/work
mkdir -p ${L_CONTAINER_ROOT_DIR}/upper
mkdir -p ${L_CONTAINER_ROOT_DIR}/merge
mount -t overlay overlay -o lowerdir=${CONTAINERS_MASTER_DATA_DIR},upperdir=${L_CONTAINER_ROOT_DIR}/upper,workdir=${L_CONTAINER_ROOT_DIR}/work ${L_CONTAINER_ROOT_DIR}/merge

初期パスワードを設定

ホスト側
sed -i \
 -e "s@^root:[^:]*@root:$(perl -E "say crypt('"${CONTAINERS_CLONE_FIRST_ROOT_PASSWD}"', '\$6\$'. crypt(rand, rand 100))")@" \
 ${L_CONTAINER_ROOT_DIR}/merge/etc/shadow

コンテナのネットワーク設定

ホスト側
mkdir -p ${L_CONTAINER_ROOT_DIR}/merge/etc/systemd/network
cat << EOS > ${L_CONTAINER_ROOT_DIR}/merge/etc/systemd/network/host0.network
[Match]
Name=host0
[Network]
Address=${CONTAINERS_CLONE_NETWORK_ADDR}/${INTERNAL_NETWORK_PREFIX}
Gateway=${INTERNAL_GATEWAY_ADDR}
EOS

コンテナのセキュリティコンテキストを初期化し、一旦アンマウント

ホスト側
restorecon -Rv ${L_CONTAINER_ROOT_DIR}/merge
umount ${L_CONTAINER_ROOT_DIR}/merge

コンテナを起動します

ホスト側
#(systemd-nspawn単体でもoverlayできるらしいのですが試していません)
mount -t overlay overlay -o lowerdir=${CONTAINERS_MASTER_DATA_DIR},upperdir=${L_CONTAINER_ROOT_DIR}/upper,workdir=${L_CONTAINER_ROOT_DIR}/work ${L_CONTAINER_ROOT_DIR}/merge
screen -S ${L_CONTAINER_NAME} systemd-nspawn -b -D ${L_CONTAINER_ROOT_DIR}/merge --network-bridge=${INTERNAL_DEV_NAME} --machine=${L_CONTAINER_NAME}

コンテナのログインプロンプトが表示されるのでroot/初期パスワードでログインし、自由にガチャガチャして下さい

備考

コンソールから抜ける場合

以下の順にキーを押す
Ctrl+a
d

コンソールに再度入る場合

ホスト側
screen -r ${L_CONTAINER_NAME}

外部からコンテナへアクセス

ポートフォワードの設定

ホスト側
#受け付けるホスト側のポート
L_HOST_PORT=11022
#プロトコル
L_PROTO=tcp
#フォワード先のコンテナのアドレス
L_CONTAINER_ADDR=10.0.0.11
#フォワード先のコンテナのポート
L_CONTAINER_PORT=22

ホストからのポートフォワードを設定

ホスト側
firewall-cmd --zone=${EXTERNAL_ZONE_NAME} --add-forward-port="port=${L_HOST_PORT}:proto=${L_PROTO}:toaddr=${L_CONTAINER_ADDR}:toport=${L_CONTAINER_PORT}"
firewall-cmd --zone=${EXTERNAL_ZONE_NAME} --add-port=${L_HOST_PORT}/${L_PROTO}
3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5