VPSにDockerでレンタルスペースを自作する

この記事はセキュリティキャンプ 修了生進捗 #seccamp OB/OG Advent Calendar 2018 – Adventarの23日目です。進捗を出していきたいと思います。

TL;DR

docker-composeでsftp/scpコンテナとsyslogコンテナを起動することでレンタルスペースをVPS上につくりました。

はじめに

VPSになぜレンタルスペースを作ることになった背景について簡単に書いてみます。私の所属するサークルでは他のサークルのWebサイトをホスティングしています。そのシステムは数年前に構築され、CentOS 6.10のまま動き続けている状態でした。具体的な環境としてはユーザーがSFTP/SCPでファイルをアップロードできるようchrootでsshdを起動してありました。 そんな古いシステムをリプレイスしようと思い、新たにDockerを使ったレンタルスペースを構築しようと考えました。

設計

従来のシステムを参考に要件を定義してみました。
  • 管理者がサークルのサーバ管理者であるため、複雑な技術や難易度の高い技術の導入は難しい。
  • 各サークルのスペースを独立させたい。
  • サーバー本体にはアクセスできないよう独立させたい。
  • 容易に環境を追加、削除、復元したい。
  • ログを残しトラブルシューティングやサポートで利用可能にする。
  • サークルごとにリソースの制限(CPU,メモリ)、ネットワークのアクセス制御を行いたい。
こうした要件からDockerによるレンタルスペースを設計しました。アーキテクチャ図が以下です。
architecture
DockerのオーケストレーションツールとしてKubernetesやDocker Swarmなどの利用も検討したものの、引き継ぐことを考え断念しました。

構築

OpenSSHサーバのDockerイメージはdockerhubにあったものの、カスタマイズが必要だったため自作しました。
FROM alpine:3.8

MAINTAINER Tomoyuki KOYAMA <webmaster@koyama.me>

ENV SSH_USER          guest22
ENV SSH_PASSWORD      L1nuxCLU8
ENV SSH_PORT          22
ENV MAX_SESSION       3
ENV PERMIT_ROOT_LOGIN no
ENV SYSLOG_SERVER     172.17.0.2
ENV SYSLOG_PORT       514

RUN apk add --update --no-cache openssh openssh-sftp-server bash tzdata rsyslog && 
    : "Configure timezone" && 
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && 
    echo "Asia/Tokyo" > /etc/timezone && 
    apk del tzdata && 
    rm -rf /var/cache/apk/* 

EXPOSE $SSH_PORT

VOLUME /www-data
VOLUME /var/log

ADD ./entrypoint.sh /
ADD ./motd /etc
# ADD ./sshd_banner /etc/ssh

CMD /bin/bash /entrypoint.sh && 
    /bin/rm -f /entrypoint.sh && 
    /usr/sbin/sshd -4 -f /etc/ssh/sshd_config && 
    /usr/sbin/rsyslogd -f /etc/rsyslog.conf -n
その他のコードはGitHubにあります。 tomoyk/ssh-rental-space: Dockerfileを書く時に、環境変数で実行時に後からポート番号やユーザ名などを変更できるように工夫しました。また、コンテナ内のタイムゾーン設定に配慮しました。ベースイメージをalpineにすることでイメージサイズが軽量になるよう注意しました。 実行 次のdocker-compose.ymlファイルを作成し、複数のコンテナを同時起動しています。
version: '3'
services:
  
  ssh-server1:
    container_name: circleA
    hostname: circleA
    image: ssh-server:latest
    restart: always
    environment:
      - SSH_USER=sshuser
      - SSH_PASSWORD=Password1
      - SSH_PORT=10022
      - SYSLOG_SERVER=syslog-server
    volumes:
      - ./www-data:/www-data/public_html
    depends_on:
      - syslog-server
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
        reservations:
          cpus: '0.25'
          memory: 20M

    # cpu_percent: 50
    # cpu_shares: 73
    # cpu_quota: 50000
    # cpuset: 0,1

    ports:
      - 10022

  syslog-server:
    container_name: common-syslog
    image: syslog-server:latest
    restart: always
    volumes:
      - ./log:/var/log

動作状況

図の左上で docker-compose up -dを実行しています。図の右のコンテナからssh接続を行っています。左中央がsyslogコンテナのログです。図の下が watch docker psの実行結果です。
docker起動時

課題

リソース制限

リソース制限の設定をdocker-composeから入れたが、forkbomb :(){ :| :& };:を実行したところフリーズしてしまいました。ファイルディスクリプタやI/Oなどの制限についてカーネル周りを中心に改めて調べてみる必要がありそうです。Wikipediaのforkbombに書かれたいた /etc/security/limits.confなども確認してみようと思います。

ネットワークのアクセス制御

ネットワークをSSH/SFTPコンテナごとに隔離したいと思っているものの、現状では出来ていません。dockerのnetworkや制御の仕組みをうまく導入したいと思います。

コンテナの監視

コンテナにSSHができなくなった時に、自動で再起動する仕組みづくりが必要だと感じました。仮にプロセスが暴走してリソース制限の最大までリソースを使い果たしても、dockerの restart=alwaysでは再起動を行ってくれません。 そのため、コンテナの状態を監視する仕組みを作り監視の自動化を行いたいと考えています。ここまでやるのであれば素直にKubernetesを使ってもいい気がします。
追記: 2019-01-01 構築が終わりました!

最後に

Dockerを完全に理解した方からアドバイスを頂けると嬉しいです。
(あと、2019年1月からのアルバイト先(都内)を探します。) 明日は hiwwさんです!

2件のコメント

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です