SoftLayerの AdventCalener2015 としての記事になります。昨年東京データセンターが開設されてからまだ1年しか立っていないのですね。

はじめに

様々なアーキテクチャのシステムが動くSoftLayerですがDockerを利用するケースも増えてきたのではないでしょうか。
Dockerも2014年から徐々に耳に聞こえて、2015年では本番で試されているお客様も多いのではないでしょうか。SoftLayerの特徴の1つであるベアメタルサーバはDockerで利用することによりそのパフォーマンスを最大限に活かすことが出来るのではないでしょうか。

実際に本番環境でDockerを利用する事を検討すると、そのままdocker engineだけでは考えること(不足してること)が結構あることに気がつくと思います。複数のサーバで動かす場合には、自社のRepositoryサーバはどこに立てるのか、ネットワークはどのようにするのか(ネットワークの話は常に悩ましいですね)、アプリケーションのデプロイはどうやってするのか、考えていくとまさにDockerの成り立ちであるようにPaaSとしての機能が必要になることに気が付きます。Dockerをよりよく動かすためにはDocker社謹製の各種ツールや、Google社のKubernetes、そして話題のMesosphe、またはDocker PaaSと呼ばれる種類のPaaS基盤まで様々あります。 2016年には、Dockerをより”上手”につかうこのような手段が本格的に利用が始まるのではないでしょうか。

今回は、RedHat社のDockerPaaSである「OpenShift」をSoftLayer上に構築してみます。サポートが必要なケースが多いと思いますが今回は気楽に試すためにOSS版である「OpenShift Origin」を利用します。

  • OSSのためソースコードが日々更新されており若干不安定な時もあります。
  • 製品版はOriginに比べてRedHat社の用意するDockerテンプレートが豊富に用意されています。

OpenShift とは

OpenShiftは、簡単に言えばDocker+Scheduler+UI+Registry+認証です(乱暴な表現ですが)。OpenShiftを利用することでユーザ管理機能やイメージを保管するRepositoryそして複数台のサーバで動かすことを制御することが出来るようになります。

NewImage

https://docs.openshift.org/latest/architecture/index.html

  • Docker Engine
  • Kuberntes
  • Docker Registry
  • Web Console

などで構成されています。

構成

今回はSoftLayer上の仮想サーバで利用してみます。
必要となるスペックは、https://docs.openshift.org/latest/install_config/install/prerequisites.html に記載されています。

  • Master (1台) 2vcpu, 8Gmem, 100Gdisk, RHELv7.1
    1. master.openshift.local
  • Node(2台)1vcpu,8Gmem, 100Gdisk, 15Gdisk(secound) ,RHELv7.1,
    1. node1.openshift.local
    2. node2.openshift.local

でオーダーをします。

プロビジョニングスクリプト

手順としては、prerequisites に従い実施する必要があります。手順をそのままスクリプトに書き出すと以下の様になりますのでこの内容をサーバオーダのプロビジョニングスクリプトとして登録して利用します。3台のサーバ全て同じ内容になります。

  • [https://bitbucket.org/snippets/tokida/8LgKG]
yum -y install wget git net-tools bind-utils iptables-services bridge-utils bash-completion
yum -y update
yum -y install \
    https://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
sed -i -e "s/^enabled=1/enabled=0/" /etc/yum.repos.d/epel.repo
yum -y --enablerepo=epel install ansible
cd ~
git clone https://github.com/openshift/openshift-ansible
cd openshift-ansible
yum -y install docker
sed -ie "s/enabled/enabled\ --insecure-registry\ 172.30.0.0\/16/"  /etc/sysconfig/docker


cat <<EOF > /etc/sysconfig/docker-storage-setup
DEVS=/dev/xvdc
VG=docker-vg
EOF
docker-storage-setup   

systemctl stop docker
rm -rf /var/lib/docker/*
systemctl restart docker

cp -p /usr/share/zoneinfo/Japan /etc/localtime

SoftLayerでオーダする際に上記のスクリプトをプロビジョニングスクリプトとして登録(インターネットでhttps経由でアクセスできる場所、Gist等)します。また導入にansibleを利用するためSSHキーも登録します。

SSHキーのコピー

masterから他のサーバにアクセスできるように rsaファイルを転送しておきます。これは先程のサーバのオーダ時に設定したキーに対応したファイル転送します。ここでは例として sl_rsa がローカルのPC上にあると仮定しています。以下のコマンドをPC上で実施します。

scp -i ~/.ssh/sl_rsa ~/.ssh/sl_rsa root@master.openshift.local:/root/.ssh/sl_rsa

起動後の事前処理

node1,node2上で名前解決のためのresolv.confを設定しておきます。

sed -i -e "s/10.0.80.11/10.160.143.35/" /etc/resolv.conf

ここからは master.openshift.local サーバ上で実施していきます。
以下の内容を /root/install.sh に保存して実行します。

#!/bin/bash

# resolv.confの変更
sed -i -e "s/10.0.80.11/10.160.143.35/" /etc/resolv.conf

openssl rsa -in ~/.ssh/sl_rsa -out ~/.ssh/sl_rsa
chmod 600 /root/.ssh/sl_rsa

cat <<EOF >> /etc/hosts
10.160.143.37 node1.openshift.local
10.160.143.38 node2.openshift.local
EOF

systemctl start dnsmasq
systemctl enable dnsmasq

yum -y install gcc libffi-devel python-devel openssl-devel
easy_install pip
#pip install cryptography
pip install pyopenssl

yum -y install httpd 

cat <<EOF > /root/.ssh/config
Host master.openshift.local
    HostName    master.openshift.local
    IdentityFile    /root/.ssh/sl_rsa
    User    root
    Port    22

Host node1.openshift.local
    HostName    node1.openshift.local
    IdentityFile    /root/.ssh/sl_rsa
    User    root
    Port    22

Host node2.openshift.local
    HostName    node2.openshift.local
    IdentityFile    /root/.ssh/sl_rsa
    User    root
    Port    22
EOF

cat <<EOF > /etc/ansible/hosts
# Create an OSEv3 group that contains the masters and nodes groups
[OSEv3:children]
masters
nodes

# Set variables common for all OSEv3 hosts
[OSEv3:vars]
# SSH user, this user should allow ssh based auth without requiring a password
ansible_ssh_user=root

# If ansible_ssh_user is not root, ansible_sudo must be set to true
#ansible_sudo=true

deployment_type=origin

# uncomment the following to enable htpasswd authentication; defaults to DenyAllPasswordIdentityProvider
#openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider', 'filename': '/etc/origin/htpasswd'}]

# host group for masters
[masters]
master.openshift.local

# host group for nodes, includes region info
[nodes]
master.openshift.local openshift_node_labels="{'region': 'infra', 'zone': 'default'}"
node1.openshift.local openshift_node_labels="{'region': 'primary', 'zone': 'east'}"
node2.openshift.local openshift_node_labels="{'region': 'primary', 'zone': 'west'}"
EOF

実行がおわったらいよいよOpenShfitを導入するAnsibleを実行します。

ansible-playbook ~/openshift-ansible/playbooks/byo/config.yml

実行結果

PLAY RECAP ********************************************************************
localhost                  : ok=13   changed=0    unreachable=0    failed=0
master.openshift.local     : ok=216  changed=56   unreachable=0    failed=0
node1.openshift.local      : ok=58   changed=19   unreachable=0    failed=0
node2.openshift.local      : ok=58   changed=19   unreachable=0    failed=0

のようになれば終了です。実際に登録されているかを確認します。

[root@master ~]# oc get nodes
NAME                     LABELS                                                                    STATUS                     AGE
master.openshift.local   kubernetes.io/hostname=master.openshift.local,region=infra,zone=default   Ready,SchedulingDisabled   2m
node1.openshift.local    kubernetes.io/hostname=node1.openshift.local,region=primary,zone=east     Ready                      56s
node2.openshift.local    kubernetes.io/hostname=node2.openshift.local,region=primary,zone=west     Ready                      48s

Registryの作成

次にこのシステム上でDockerのRegistryをデプロイします。OpenShiftでは全てOpenShiftによりコンテナが管理されるためたんに
docker run するわけにはいきません。

reguserにてポリシーを作ります。

htpasswd -c /etc/origin/openshift-htpasswd reguser
oadm policy add-role-to-user system:registry reguser 

Registryを登録します。

[root@master ~]# oadm registry --config=/etc/origin/master/admin.kubeconfig --credentials=/etc/origin/master/openshift-registry.kubeconfig
DeploymentConfig "docker-registry" created
Service "docker-registry" created

上記でサービスとしてregistyrが起動します。

[root@master ~] # oc logs docker-registry-1-uwfy7
time="2015-12-03T16:54:37Z" level=info msg="version=v2.0.0+unknown"
time="2015-12-03T16:54:37Z" level=info msg="redis not configured" instance.id=d905f1de-307e-449a-a212-f4d07e53118b
time="2015-12-03T16:54:37Z" level=info msg="using inmemory layerinfo cache" instance.id=d905f1de-307e-449a-a212-f4d07e53118b
time="2015-12-03T16:54:37Z" level=info msg="Using Origin Auth handler"
time="2015-12-03T16:54:37Z" level=info msg="listening on :5000" instance.id=d905f1de-307e-449a-a212-f4d07e53118b
time="2015-12-03T16:54:37Z" level=info msg="Starting upload purge in 59m0s" instance.id=d905f1de-307e-449a-a212-f4d07e53118b

より詳細に情報が見たい場合には以下の describe コマンドで確認が出来ます。

oc describe pod docker-registry-1-uwfy7

この時点ではサービスは以下の様なものが稼働しています。

[root@master ~]# oc get service
NAME              CLUSTER_IP      EXTERNAL_IP   PORT(S)                 SELECTOR                  AGE
docker-registry   172.30.228.81   <none>        5000/TCP                docker-registry=default   5m
kubernetes        172.30.0.1      <none>        443/TCP,53/UDP,53/TCP   <none>                    18m

Routerの作成

“Router”は、これから作成するアプリケーションなどをURIから正しいコンテナに接続するための機能です。この機能があると複数のノードのどこでコンテナが起動しても、そのリクエストされるURIから正しいノードにリクエストを転送する事ができます。OpenShiftではBIG-IPやHA_Proxyでこの機能を実現します。

[root@master ~]# oadm router router --credentials=/etc/origin/master//openshift-router.kubeconfig --service-account=router
password for stats user admin has been set to v1ek6STO5Q
DeploymentConfig "router" created
Service "router" created

ルータが稼働するとこのような状態になります

[root@master ~]# oc get service
NAME              CLUSTER_IP      EXTERNAL_IP   PORT(S)                 SELECTOR                  AGE
docker-registry   172.30.228.81   <none>        5000/TCP                docker-registry=default   17m
kubernetes        172.30.0.1      <none>        443/TCP,53/UDP,53/TCP   <none>                    29m
router            172.30.201.22   <none>        80/TCP                  router=router             28s
[root@master ~]# oc get pods
NAME                      READY     STATUS    RESTARTS   AGE
docker-registry-1-uwfy7   1/1       Running   0          16m
router-1-q3b8g            1/1       Running   0          29s

補足

  • Routerを作成する際にマニュアルには色々書いていますが、ServiceAccountの作成のくだりはインストーラーで登録済みなので不要です。
  • 最終的に外部に公開するアプリケーションの場合には、名前でアプリケーションにリクエストします。任意のアプリケーション名.ホスト名(FDQN)が利用可能ですが Routerが動くノードのIPアドレスとして解決できるようにします。
  • 例えば,http://sample.openshif.localというアプリケーションをデプロイする場合には sample.openshift.localの名前解決が出来る筆お湯がありその際のIPアドレスは routerが動いいてるノードのIPアドレスになります。
  • 公開するアプリケーションのドメインは /etc/origin/master/master-config.yaml の subdomain で定義されています。
  • 公開されたアプリの名称も oc expose service hello –hostname=FDQN で変更することが出来ます。

アプリケーションを作る

ブラウザからコンソールにアクセスします。http://master.openshift.local:8443/console でアクセスします。ユーザはrootでログインしてみます。

NewImage

プロジェクトが無いので新規に作成をする画面が表示されます。

NewImage

必要な情報を記載します。

NewImage

次にアプリケーションのテンプレートを選択する画面が表示されます。今回は PHP5.5を選択肢てみます。

NewImage

アプリケーションの名前(samplephp)とGitRepositoryURLを指定します。

NewImage

作成をクリックするとアプリケーションを利用するための情報が表示されます。

NewImage

起動がおわると以下の画面が表示されます。

NewImage

今回公開されているアプリケーション名が「samplephp-1st-application.router.default.svc.cluster.local 」になっているのでこれを変更します。

[root@master ~]# oc login
Authentication required for https://master.openshift.local:8443 (openshift)
Username: root
Password:
Login successful.

Using project "1st-application".
[root@master ~]# oc get route
NAME        HOST/PORT                                                    PATH      SERVICE     LABELS          INSECURE POLICY   TLS TERMINATION
samplephp   samplephp-1st-application.router.default.svc.cluster.local             samplephp   app=samplephp

変更にあたって既存のrouteを削除して追加します。

[root@master ~]# oc delete route samplephp
route "samplephp" deleted
[root@master ~]# oc expose service samplephp --hostname=sample.openshift.local
route "samplephp" exposed
[root@master ~]# oc get route
NAME        HOST/PORT                PATH      SERVICE     LABELS          INSECURE POLICY   TLS TERMINATION
samplephp   sample.openshift.local             samplephp   app=samplephp

これでこのURLに対してブラウザでアクセスをしてみます。

NewImage

無事に動いていればCakePHPの画面が表示されます。

備考

  • 指定するカスタムのURIの宛先は routerが動いているNodeのIPアドレスです。Routerを高可用性を持たせるためには別途そのための構成を取る必要があります。動いているサーバを見つけるためには , oc get podsでrouterのNAMEを取得します。そして oc describe pod <NAME> でNode: という項目に動いているノード情報が表示されます。

まとめ

今回は簡単に動かすところまでをおいました。最小限での構成としていますが実際には複数台のMaster構成やロケーションなどを考慮したノードの設計を作ることも可能なので、SoftLayerのデータセンタに合わせて場所別にリソースを定義した入りすることが出来そうです。

DockerやPaaSという環境は、アプリケーションをデプロイするための仕組みですのでどの様にDockerアプリケーションをBuildしてデプロイするのかを次の機会で書きたいと思います。