2018년 1월 29일 월요일

IBM AC922의 2-socket 간의 대역폭은 얼마인가 ?

먼저, 이건 IBM의 공식 발표 수치가 아니라 현재까지 발표된 기술 자료들에 근거한 산술 계산임을 밝힙니다. 

IBM AC922은 POWER9 processor와 NVIDIA V100 GPU를 PCIe 대신 NVLink 2.0으로 연결했다는, 업계 유일무이한 아키텍처 외에도 자랑할 만한 점이 있습니다.  즉, 6개의 NVLink를 3개씩묶어, NVLink의 50GB/s (25+25)가 아닌 150GB/s의 대역폭으로 GPU와 GPU, 그리고 CPU와 GPU를 연결한다는 점입니다.

같은 NVLink V100을 사용하는 x86 processor 기반의 다른 서버들에서는 CPU와 GPU는 고작 32GB/s의 PCIe로 연결하고, 또 GPU와 GPU 간도 NVLink 하나로 연결되기 때문에 고작 50GB/s로 연결되는 점과 비교되는 부분입니다. 

하지만 AC922의 각 CPU 소켓에 연결된 2개의 GPU cluster간의 연결은 POWER 프로세서의 SMP 버스를 연결해야 한다는 점은 여전합니다.   기존 POWER8 + P100 구조인 Minsky 서버에서는 이 SMP X bus의 대역폭이 38.4 GB/s 였기 때문에, 40 GB/s인 NVLink 1.0에 비해 손색이 별로 없었습니다.   그런데, AC922에서는 이 SMP X bus의 대역폭이 얼마일까요 ?  아직 IBM에서 AC922의 아키텍처에 대한 상세 redbook이 나오지 않아 정식으로 발표된 자료가 없습니다.


(이 그림에서 왼쪽은 P100을 장착한 DGX-1의 아키텍처입니다.  이제 4개의 NVLink 1.0 port를 장착한 P100 대신 6개의 NVLink 2.0을 장착한 V100을 탑재했으니, 아마 GPU 간을 엮는 NVLink topology가 조금 바뀌었을 것 같은데, 그림을 못 찾겠네요.  대신 기존의 링크 당 40GB/s 대신 50GB/s로 올라간 것은 확실합니다.)


구글링을 해보니 답이 나옵니다.  아래 PDF 문서에, AC922의 두 processor socket을 연결하는 SMP X bus의 spec이 "X-Bus 4B @ 16GHz"라고 나온 것입니다.   기존 Minsky 서버의 SMP X bus의 spec은 "8B @ 4.8 GHz"였습니다.



(출처 : https://www.ibm.com/developerworks/community/wikis/form/anonymous/api/wiki/61ad9cf2-c6a3-4d2c-b779-61ff0266d32a/page/1cb956e8-4160-4bea-a956-e51490c2b920/attachment/9a8eabe8-10b8-4a8e-aebe-3a3845b71c0f/media/Power%20Systems%20AC922%20Intro%2011December2017%20.pdf )

이 spec을 대역폭(GB/s)으로 환산하는 것은 어떻게 하는 것일까요 ?  다음 문서에 나옵니다. 

https://www.redbooks.ibm.com/redpapers/pdfs/redp5405.pdf

기존 Minsky 서버의 SMP X bus 대역폭 :  8 bytes * 4.8 GHz = 38.4 GB/s

AC922 서버의 SMP X bus 대역폭 : 4 bytes * 16 GHz = 64 GB/s

즉, AC922 서버는 NVLink 1.0 80GB/s에서 NVLink 2.0 150GB/s로의 비율만큼, SMP X bus의 속도도 끌어올린 것입니다.   이 64GB/s라는 속도는 NVLink 2.0 1개 link인 50GB/s보다 오히려 더 뛰어난 속도로서, 4개 GPU를 이용한 Deep Learning에 충분한 속도를 제공합니다.

한편, x86 서버 프로세서 중 최신인 Skylake Scalable Processor는 기존 Broadwell의 2 x QPI @ 9.6 GT/s를 3 x UPI @ 10.4 GT/s로 업그레이드했습니다.   (출처 : https://www.servethehome.com/intel-xeon-scalable-processor-family-platform-level-overview/ )   이 GT/s를 Gbps로 변환하면 PCIe Gen3 기준으로 대략 98%이므로 (출처 : https://paolozaino.wordpress.com/2013/05/21/converting-gts-to-gbps/ ) 대략 30.72 Gbps가 됩니다.   ( 3 x 10.4 x 128/130 = 30.72 ) 

2018년 1월 24일 수요일

infiniband를 이용한 caffe DDL에서의 색다른 error와 그 해결책


caffe-ibm이 자랑하는 기능 중 하나인 DDL (Distributed Deep Learning)은 여러대의 GPU 서버에 들어있는 GPU들을 OpenMPI로 연결하여 하나의 큰 모델을 training할 수 있도록 해주는 기능입니다.   당연히 여러대의 GPU 서버를 연결하는 network의 latency와 bandwidth에 큰 영향을 받습니다.  여기서는 minsky1과 minsky2라는 hostname의 서버에, IP over Infiniband를 구성하고, 그 interface에 각각 ib1과 ib2라는 IP name을 /etc/hosts에 등록하여 별도의 고속 private network을 구성하여 DDL을 해봤습니다.

이 경우 4-GPU 서버가 2대이고 하나의 network으로 물려있으므로 그 topology를 알려주는 rank file은 아래와 같이 하면 됩니다.

$ cat 4x2x1.rf 

rank 0=ib1         slot=0:0-3
rank 2=ib1         slot=0:4-7
rank 4=ib1         slot=1:0-3
rank 6=ib1         slot=1:4-7



rank 1=ib2         slot=0:0-3
rank 3=ib2         slot=0:4-7
rank 5=ib2         slot=1:0-3
rank 7=ib2         slot=1:4-7


그런데, 막상 돌려보니 아래와 같이 error 메시지가 나옵니다. 

$ mpirun -x PATH -x LD_LIBRARY_PATH -n 8 -rf 4x2x1.rf caffe train --solver=solver.prototxt -gpu 0 -ddl "-mode b:4x1x1 -dev_sync 1"
--------------------------------------------------------------------------
Failed to create a completion queue (CQ):
Hostname: minsky1
Requested CQE: 16384
Error:    Cannot allocate memory
Check the CQE attribute.
--------------------------------------------------------------------------
--------------------------------------------------------------------------
Open MPI has detected that there are UD-capable Verbs devices on your
system, but none of them were able to be setup properly.  This may
indicate a problem on this system.
You job will continue, but Open MPI will ignore the "ud" oob component
in this run.
Hostname: minsky1
--------------------------------------------------------------------------
--------------------------------------------------------------------------
Failed to create a completion queue (CQ):
Hostname: minsky2
Requested CQE: 16384
Error:    Cannot allocate memory
Check the CQE attribute.
--------------------------------------------------------------------------
--------------------------------------------------------------------------
Open MPI has detected that there are UD-capable Verbs devices on your
system, but none of them were able to be setup properly.  This may
indicate a problem on this system.
You job will continue, but Open MPI will ignore the "ud" oob component
in this run.
Hostname: minsky2
--------------------------------------------------------------------------
--------------------------------------------------------------------------
The rankfile that was used claimed that a host was either not
allocated or oversubscribed its slots.  Please review your rank-slot
assignments and your host allocation to ensure a proper match.  Also,
some systems may require using full hostnames, such as
"host1.example.com" (instead of just plain "host1").
  Host: minsky1
--------------------------------------------------------------------------

이건 2가지 error입니다.  하나는 "Cannot allocate memory"이고, 다른 하나는 "either not
allocated or oversubscribed its slots" 인데, 각각 다른 원인에 의한 것입니다.


1)  "Cannot allocate memory"  error

이건 limits 값 때문입니다.  다음과 같이 ulimit 값을 보면 max locked memory가 기본으로는 64로 되어 있습니다.  

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 15880
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 15880
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

이걸 풀어주기 위해서는 아래와 같이 limits.conf의 맨 끝에 해당 user에 대한 limit를 풀어준 뒤, 반드시 re-login을 하셔야 합니다.   이걸로 해결됩니다.

$ sudo vi /etc/security/limits.conf
...
user1   soft    memlock   -1
user1   hard    memlock   -1


2) "either not allocated or oversubscribed its slots"  error

이건 정말 제가 예상 못 했던 것인데, 구글링을 해보니 뜻 밖에도 mpirun 등의 MPI command는 IP name이 아니라 hostname에 민감한 것 같습니다.  즉, 저 GPU 서버들의 hostname이자 ethernet interface의 IP name이 minsky1 (10.1.1.1), minsky2 (10.1.1.2)이고, infiniband interface의 IP name이 ib1 (9.1.1.1), ib2 (9.1.1.2)인데, 이렇게 hostname과 rank file 안에 들어가는 IP name이 각각 다르면 안되나 봅니다.

이 경우 다음과 같이 두 서버의 hostname을 IB interface의 이름인 ib1, ib2로 각각 바꿔주면 해결이 됩니다.

$ hostnamectl set-hostname ib1
$ hostnamectl set-hostname ib2


2018년 1월 19일 금요일

AC922 Redhat 환경에서 source code로부터 caffe build하기


AC922 Redhat 환경에서는 아직은 정식으로 PowerAI가 full 지원되지 않으며, 이는 2018년 2Q로 예정되어 있습니다.   그러나 source code로부터 빌드하는 것은 언제나 하기 나름입니다.

지난 포스팅에서는 AC922에서 Tensorflow 1.4.1을 빌드하는 것을 보여드렸는데, 이번에는 caffe (물론 bvlc-caffe)를 빌드합니다.   이번에는 IBM 이보란 과장께서 수고해주셨습니다.  본문은 아래 이보란 과장이 운영하는 블로그를 click 하십시요.

http://shareithw.blogspot.kr/2018/01/bvlc-caffe-rhel-power9-ppc64le.html

2018년 1월 15일 월요일

AC922에서 Ubuntu 기반 container image로 caffe 및 tensorflow 수행하기

좋은 소식입니다.  원래 발표에서는 AC922에서는 2018년 2Q가 되어야 정식으로 Ubuntu가 지원될 예정이었습니다.  caffe나 tensorflow 등도 그때나 되어야 지원될 예정이었고요. 

오늘 테스트해보니 AC922의 CUDA9.1 + Redhat 7.4 + nvidia-docker v1 환경에서 테스트해보니, 기존 ubuntu 16.04에서 빌드해놓았던 tensorflow 1.3과 caffe 1.0이 다 잘 돌아갑니다.

그리고 성능도 기존 Minsky P100에서보다 약 1.7~1.8배 정도 나옵니다.  V100의 공식 TFLOPS 성능이 P100의 1.5배인 것을 생각하면 이는 POWER9과 NVLink 2.0 덕분인 것 같습니다.

[root@ac922 ~]# nvidia-docker run -ti --rm -v /nvme:/nvme bsyu/tf1.3-ppc64le:v0.1 bash

root@2be8a3ffc5fd:/nvme/models/tutorials/image/cifar10# which python
/opt/anaconda3/bin/python

root@2be8a3ffc5fd:/nvme/models/tutorials/image/cifar10# time python cifar10_multi_gpu_train.py --batch_size 512
...
2018-01-15 13:10:45.808267: step 8220, loss = 0.75 (27044.5 examples/sec; 0.019 sec/batch)
2018-01-15 13:10:46.585492: step 8230, loss = 0.60 (27071.8 examples/sec; 0.019 sec/batch)
2018-01-15 13:10:47.353298: step 8240, loss = 0.59 (26355.8 examples/sec; 0.019 sec/batch)
2018-01-15 13:10:48.130751: step 8250, loss = 0.67 (26219.3 examples/sec; 0.020 sec/batch)
2018-01-15 13:10:48.909557: step 8260, loss = 0.61 (27011.5 examples/sec; 0.019 sec/batch)
2018-01-15 13:10:49.681004: step 8270, loss = 0.65 (27131.1 examples/sec; 0.019 sec/batch)


단, 이런 성능을 내기 위해서는 예전과 마찬가지로 GPU auto boost를 해줘야 하며, V100에 대해서는 다음과 같이 해주시기 바랍니다.

[root@ac922 ~]# cat /etc/rc.local
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.

touch /var/lock/subsys/local

/usr/bin/nvidia-smi -pm ENABLED
/usr/bin/nvidia-smi -ac 877,1530
/usr/sbin/ppc64_cpu --smt=off
sleep 30
/usr/bin/cpupower frequency-set --governor performance
/usr/bin/nvidia-docker-plugin &


또한 이렇게 docker container를 이용할 경우, cuda를 initialize하는데 시간이 꽤 오래 걸립니다.  이건 Redhat 위에서 ubuntu 기반 container를 띄우기 때문인지, 아니면 nvidia-docker v1을 사용하기 때문인지, 아니면 CUDA 9의 문제인지 아직 불분명합니다.

그리고 그대로 nvidia-smi를 수행하면 failed call to cuInit: CUDA_ERROR_NOT_INITIALIZED error가 납니다.  그 문제는 아래와 같이 해결 가능합니다.  아래 내용은 IBM 이보란 과장이 정리해주었습니다.

# vi /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
options nouveau modeset=0
# sudo dracut --force
# vi /usr/lib/systemd/system/nvidia-persistenced.service
[Unit]
Description=NVIDIA Persistence Daemon
Wants=syslog.target

[Service]
Type=forking
PIDFile=/var/run/nvidia-persistenced/nvidia-persistenced.pid
Restart=always
ExecStart=/usr/bin/nvidia-persistenced --verbose
ExecStopPost=/bin/rm -rf /var/run/nvidia-persistenced

[Install]
WantedBy=multi-user.target
# sudo systemctl enable nvidia-persistenced

$ vi /lib/udev/rules.d/40-redhat.rules  (아래 줄을 #으로 comment-out)
#SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online"

# /usr/bin/nvidia-persistenced --verbose
# sudo yum install freeglut-devel libX11-devel libXi-devel libXmu-devel make mesa-libGLU-devel
Error downloading packages:
  libXext-devel-1.3.3-3.el7.ppc64le: [Errno 256] No more mirrors to try.
  libXdamage-devel-1.1.4-4.1.el7.ppc64le: [Errno 256] No more mirrors to try. (생략)
==> 설치부분은 위와 같이 다운로드 에러가 납니다만, 그냥 무시하고 넘어갔습니다.
이후 PYTHONPATH, PATH, LD_LIBRARY_PATH 설정 후에 tensorflow 1.4 로 cifar10이든, mnist 든 수행하면 다음의 에러가 납니다. 
[root@ac922 cifar10]# python cifar10_train.py
Traceback (most recent call last):
  File "cifar10_train.py", line 42, in <module>
    import tensorflow as tf
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/__init__.py", line 24, in <module>
    from tensorflow.python import *
  File "/opt/anaconda3/lib/python3.6/site-packages/tensorflow/python/__init__.py", line 30, in <module>
    import traceback
  File "/opt/anaconda3/lib/python3.6/traceback.py", line 5, in <module>
    import linecache
  File "/opt/anaconda3/lib/python3.6/linecache.py", line 11, in <module>
    import tokenize
  File "/opt/anaconda3/lib/python3.6/tokenize.py", line 33, in <module>
    import re
  File "/opt/anaconda3/lib/python3.6/re.py", line 142, in <module>
    class RegexFlag(enum.IntFlag):
AttributeError: module 'enum' has no attribute 'IntFlag'
enum34가 설치되어 있어서 발생하는 에러인데, Python 3.4 버전 이상부터는 enum34와 호환이 되지 않아서 이를 삭제해야 한다고 합니다. 삭제를 위해, 우선 PYTHONPATH를 Python 2.7 경로로 바꿔줍니다.
# export PYTHONPATH=/opt/DL/tensorflow/lib/python2.7/site-packages
# pip uninstall enum34
# export PYTHONPATH=<python3.6/site-packages의 경로로 재설정>
# export PYTHONPATH=/opt/anaconda3/lib/python3.6/site-packages
그 다음, cifar10 이든 mnist를 수행하면 enum 관련 에러는 발생하지 않고, nvidia-smi 에서는 unknown error 대신 GPU 메모리 상태 정보를 제대로 띄우는 것을 확인할 수 있습니다. 






2018년 1월 13일 토요일

AC922 Redhat python3 환경에서 tensorflow 1.4.1을 source로부터 빌드하기

먼저번 포스팅에서 보신 것처럼 AC922 Redhat 7.4 환경에서 tensorflow 1.4를 사용하기 위한 공식적인 방법은 IBM에서 AC922 구매 고객에게만 별도로 제공하는 Tensorflow Technical Preview를 이용하는 것입니다.  그러나 이것은 아직은 python2만 지원하므로, python3에서는 사용할 수 없습니다.  (2018 2Q에는 다 지원될 예정)

하지만 그래도 python3에서 tensorflow 1.4를 사용할 방법이 전혀 없는 것은 아닙니다.  직접 빌드하면 됩니다.

여기서는 Tensorflow Technical Preview에 포함된 bazel 0.5.4를 이용하면 됩니다.  먼저 다음과 같이 Anaconda3의 path를 설정한 뒤, 이어서 Tensorflow Technical Preview에 포함된 bazel 0.5.4의 PATH를 맨 앞으로 설정하면 됩니다.

[root@ac922 nvme]# export PATH="/opt/DL/bazel/bin:/opt/anaconda3/bin:$PATH"

이어서 필요한 protobuf 등과 기타 필요 파일셋을 설치합니다.

[root@ac922 ~]# conda install protobuf

[root@ac922 ~]# which protoc
/opt/anaconda3/bin/protoc

[root@ac922 ~]# export PROTOC=/opt/anaconda3/bin/protoc

[root@ac922 nvme]# yum install apr-util-devel.ppc64le ant cmake.ppc64le automake.noarch ftp libtool.ppc64le libtool-ltdl-devel.ppc64le apr-util-openssl.ppc64le openssl-devel.ppc64le  golang.ppc64le golang-bin.ppc64le


(옵션 :  Tensorflow Technical Preview에 포함된 bazel 0.5.4를 사용하는 대신 다음과 같이 bazel 최신 버전의 bazel-*-dist.zip을 download 받아서 빌드를 해도 됩니다.

[root@ac922 nvme]# wget https://github.com/bazelbuild/bazel/releases/download/0.8.1/bazel-0.8.1-dist.zip

[root@ac922 nvme]# mkdir bazel-0.8.1 && cd bazel-0.8.1

[root@ac922 bazel-0.8.1]# unzip ../bazel-0.8.1-dist.zip

[root@ac922 bazel-0.8.1]# ./compile.sh

[root@ac922 bazel-0.8.1]# cp output/bazel /usr/local/bin

옵션 부분 끝)


이제 tensorflow source를 다운로드 받습니다.

[root@ac922 nvme]# git clone https://github.com/tensorflow/tensorflow

[root@ac922 nvme]# cd tensorflow

[root@ac922 tensorflow]# git checkout tags/v1.4.1

[root@ac922 tensorflow]# conda install wheel numpy six

[root@ac922 tensorflow]# export LD_LIBRARY_PATH=/usr/local/cuda-9.1/lib64:/usr/lib64:/usr/lib:/usr/local/lib64:/usr/local/lib:$LD_LIBRARY_PATH

[root@ac922 tensorflow]# export PATH=/opt/DL/bazel/bin:$PATH

다음으로는 평범하게 ./configure 뒤에 bazel build를 하면 되는데... 그러면 다음과 같이 boringssl 관련 error가 납니다.

[root@ac922 tensorflow]# bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package
....
ERROR: /root/.cache/bazel/_bazel_root/c33b26ecf6ca982d66935dcfbfc79c56/external/boringssl/BUILD:118:1: C++ compilation of rule '@boringssl//:crypto' failed (Exit 1).
In file included from external/boringssl/src/crypto/fipsmodule/bcm.c:92:0:
external/boringssl/src/crypto/fipsmodule/sha/sha1.c:125:6: error: static declaration of 'sha1_block_data_order' follows non-static declaration
 void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num);
      ^
In file included from external/boringssl/src/crypto/fipsmodule/bcm.c:91:0:
external/boringssl/src/crypto/fipsmodule/sha/sha1-altivec.c:190:6: note: previous definition of 'sha1_block_data_order' was here
 void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num) {
      ^
Target //tensorflow/tools/pip_package:build_pip_package failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 77.133s, Critical Path: 20.67s


이 문제의 해결을 위해서는 다음의 patch 2개가 필요합니다.   patch 내용은 맨 아래에 별도로 달아두겠습니다.

[root@ac922 tensorflow]# patch < 120-curl-build-fix.patch
can't find file to patch at input line 5
Perhaps you should have used the -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/third_party/curl.BUILD b/third_party/curl.BUILD
|index 882967d..3c48dfa 100644
|--- a/third_party/curl.BUILD
|+++ b/third_party/curl.BUILD
--------------------------
File to patch: third_party/curl.BUILD
patching file third_party/curl.BUILD
[root@ac922 tensorflow]# patch < 140-boring-ssl.patch
can't find file to patch at input line 5
Perhaps you should have used the -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/third_party/boringssl/add_boringssl_s390x.patch b/third_party/boringssl/add_boringssl_s390x.patch
|index 8b42d10..26c51a3 100644
|--- a/third_party/boringssl/add_boringssl_s390x.patch
|+++ b/third_party/boringssl/add_boringssl_s390x.patch
--------------------------
File to patch: third_party/boringssl/add_boringssl_s390x.patch
patching file third_party/boringssl/add_boringssl_s390x.patch


이 patch들을 적용하고도 "fatal error: math_functions.hpp: No such file or directory"가 발생합니다.  이는 아래 URL을 참조하여 tensorflow/workspace.bzl을 다음과 같이 수정하면 됩니다.

# from https://github.com/tensorflow/tensorflow/issues/15389 & https://github.com/angersson/tensorflow/commit/599dc70e9e478b4bc24fb2329c175ea978ef620a

[root@ac922 tensorflow]# vi tensorflow/workspace.bzl
...
  native.new_http_archive(
      name = "eigen_archive",
      urls = [
#          "https://bitbucket.org/eigen/eigen/get/429aa5254200.tar.gz",
#          "http://mirror.bazel.build/bitbucket.org/eigen/eigen/get/429aa5254200.tar.gz",
          "https://bitbucket.org/eigen/eigen/get/034b6c3e1017.tar.gz",
          "http://mirror.bazel.build/bitbucket.org/eigen/eigen/get/034b6c3e1017.tar.gz",
      ],
#      sha256 = "61d8b6fc4279dd1dda986fb1677d15e3d641c07a3ea5abe255790b1f0c0c14e9",
#      strip_prefix = "eigen-eigen-429aa5254200",
      sha256 = "0a8ac1e83ef9c26c0e362bd7968650b710ce54e2d883f0df84e5e45a3abe842a",
      strip_prefix = "eigen-eigen-034b6c3e1017",
      build_file = str(Label("//third_party:eigen.BUILD")),
  )

이제 ./configure와 bazel build를 수행합니다.

[root@ac922 tensorflow]# ./configure
...
Do you wish to build TensorFlow with Google Cloud Platform support? [Y/n]: n
...
Do you wish to build TensorFlow with Amazon S3 File System support? [Y/n]: n
...
Do you wish to build TensorFlow with CUDA support? [y/N]: y
Please specify the CUDA SDK version you want to use, e.g. 7.0. [Leave empty to default to CUDA 8.0]: 9.1
Please specify the location where CUDA 9.1 toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]: /usr/local/cuda-9.1
Please specify the cuDNN version you want to use. [Leave empty to default to cuDNN 6.0]: 7
Please specify the location where cuDNN 7.0 library is installed. Refer to README.md for more details. [Default is /usr/local/cuda-9.1]:/usr/local/cuda-9.1/targets/ppc64le-linux/lib
Please note that each additional compute capability significantly increases your build time and binary size. [Default is: 3.5,5.2]7.0
...
Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -mcpu=native]: -mcpu=power8
(아직 gcc에 -mcpu=power9이 없으므로 power8으로 대체해야 합니다.  아무 것도 주지않으면 default로 power9이 되면서 error가 납니다.)
...


[root@ac922 tensorflow]# bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package

[root@ac922 tensorflow]# bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

결과로 생긴 tensorflow-1.4.1-cp36-cp36m-linux_ppc64le.whl를 pip로 설치하면 됩니다.

[root@ac922 tensorflow]# ls -l /tmp/tensorflow_pkg
total 67864
-rw-r--r--. 1 root root 69491907 Jan 13 12:23 tensorflow-1.4.1-cp36-cp36m-linux_ppc64le.whl

[root@ac922 tensorflow]# which pip
/opt/anaconda3/bin/pip

[root@ac922 tensorflow]# pip install /tmp/tensorflow_pkg/tensorflow-1.4.1-cp36-cp36m-linux_ppc64le.whl

[root@ac922 tensorflow]# conda list | grep tensor
tensorflow                1.4.1                     <pip>
tensorflow-tensorboard    0.4.0rc3                  <pip>

이제 python3에서 tensorflow 1.4.1을 사용하실 수 있게 되었습니다.


PS.  위에서 적용했던 patch 파일들(140-boring-ssl.patch & 120-curl-build-fix.patch) 내용입니다.

[root@ac922 tensorflow]# cat 140-boring-ssl.patch
diff --git a/third_party/boringssl/add_boringssl_s390x.patch b/third_party/boringssl/add_boringssl_s390x.patch
index 8b42d10..26c51a3 100644
--- a/third_party/boringssl/add_boringssl_s390x.patch
+++ b/third_party/boringssl/add_boringssl_s390x.patch
@@ -131,3 +131,19 @@ index 6b645e61..c90b7beb 100644
          "//conditions:default": ["-lpthread"],
      }),
      visibility = ["//visibility:public"],
+diff --git a/src/crypto/fipsmodule/sha/sha1.c b/src/crypto/fipsmodule/sha/sha1.c
+index 7ce0193..9791fa5 100644
+--- a/src/crypto/fipsmodule/sha/sha1.c
++++ b/src/crypto/fipsmodule/sha/sha1.c
+@@ -63,9 +63,9 @@
+ #include "../../internal.h"
+
+
+-#if !defined(OPENSSL_NO_ASM) &&                         \
++#if (!defined(OPENSSL_NO_ASM) &&                         \
+     (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
+-     defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \
++     defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) || \
+      defined(OPENSSL_PPC64LE))
+ #define SHA1_ASM
+ #endif


[root@ac922 tensorflow]# cat 120-curl-build-fix.patch
diff --git a/third_party/curl.BUILD b/third_party/curl.BUILD
index 882967d..3c48dfa 100644
--- a/third_party/curl.BUILD
+++ b/third_party/curl.BUILD
@@ -479,7 +479,12 @@ genrule(
         "#  define HAVE_SSL_GET_SHUTDOWN 1",
         "#  define HAVE_STROPTS_H 1",
         "#  define HAVE_TERMIOS_H 1",
+        "#if defined(__powerpc64__) || defined(__powerpc__)",
+        "#  define OS \"powerpc64le-ibm-linux-gnu\"",
+        "#  undef HAVE_STROPTS_H",
+        "#else",
         "#  define OS \"x86_64-pc-linux-gnu\"",
+        "#endif",
         "#  define RANDOM_FILE \"/dev/urandom\"",
         "#  define USE_OPENSSL 1",
         "#endif",


아울러 위 과정에서 빌드한 tensorflow 1.4.1 for python3의 wheel 파일을 아래 google drive에 올려두겠습니다.  품질을 책임질 수 있는 파일이 아닌 점은 양해부탁드립니다.

https://drive.google.com/open?id=1_C2BZJ9G6HekxV2U6mil2sVf3WJIlh-n

AC922 "Newell" Redhat 7.4 환경에서 Tensorflow Technical Preview 설치하기

먼저, 인터넷 연결이 없는 환경을 위해 ISO 이미지를 이용하여 redhat local repository를 만듭니다.

[root@ac922 nvme]# ls -l *.iso
-rw-r--r--. 1 root root 3187027968 Jan 10 12:42 rhel-alt-server-7.4-ppc64le-dvd.iso

[root@ac922 nvme]# mount -t iso9660 -o loop rhel-alt-server-7.4-ppc64le-dvd.iso /mnt
mount: /dev/loop0 is write-protected, mounting read-only

[root@ac922 nvme]# vi /etc/yum.repos.d/local.repo
[local]
baseurl=file:///mnt/
gpgcheck=0


CUDA 설치를 위한 사전 필요 파일셋을 설치합니다.

[root@ac922 ~]# sudo yum -y install wget nano bzip2

[root@ac922 ~]# wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

[root@ac922 ~]# rpm -ihv epel-release-latest-7.noarch.rpm

[root@ac922 ~]# yum update kernel kernel-tools kernel-tools-libs kernel-bootwrapper gcc openssh-server openssh-clients openssl-devel python-devel kernel-devel-uname-r elfutils-libelf-devel

[root@ac922 ~]# yum update


그리고 Tensorflow Technical Preview에서 요구하는대로, 아래 파일을 수정한 뒤 리부팅합니다.

[root@ac922 ~]# vi /lib/udev/rules.d/40-redhat.rules   # 다음 줄을 comment-out 처리
...
#SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/uname -p", RESULT!="s390*", ATTR{state}=="offline", ATTR{state}="online"

[root@ac922 ~]# shutdown -r now


이제 Anaconda를 다운받고 설치합니다.  참고로, IBM에서 제공하는 Tensorflow Technical Preview는 아직 공식적으로는 TF1.4 with python2만 지원하며, python3를 비롯한 정식 지원은 2018년 2Q에 예정되어 있습니다.   여기서는 python3에서도 TF1.4.1을 빌드할 것이므로, 일단 Anaconda3도 설치합니다.

[root@ac922 nvme]# wget https://repo.continuum.io/archive/Anaconda2-5.0.0-Linux-ppc64le.sh
[root@ac922 nvme]# wget https://repo.continuum.io/archive/Anaconda3-5.0.0-Linux-ppc64le.sh

[root@ac922 nvme]# ./Anaconda2-5.0.0-Linux-ppc64le.sh
...
[/root/anaconda2] >>> /opt/anaconda2

[root@ac922 nvme]# ./Anaconda3-5.0.0-Linux-ppc64le.sh
...
[/root/anaconda3] >>> /opt/anaconda3

여기서는 anaconda2를 써야 합니다.  이 Tensorflow ESP는 python 2.x만 지원하기 때문입니다.

[root@ac922 nvme]# export PATH="/opt/anaconda2/bin:$PATH"


이제 CUDA를 설치합니다. 

[root@ac922 nvme]# rpm -Uvh cuda-repo-rhel7-9-1-local-9.1.85-1.ppc64le.rpm

[root@ac922 nvme]# wget ftp://fr2.rpmfind.net/linux/fedora-secondary/development/rawhide/Everything/ppc64le/os/Packages/d/dkms-2.4.0-1.20170926git959bd74.fc28.noarch.rpm

[root@ac922 nvme]# rpm -Uvh dkms-2.4.0-1.20170926git959bd74.fc28.noarch.rpm

[root@ac922 nvme]# yum install cuda

[root@ac922 nvme]# cd /usr/local

[root@ac922 local]# tar -ztvf /nvme/cudnn-9.1.tgz
-r--r--r-- erisuser/erisuser 107140 2017-11-01 21:13 cuda/targets/ppc64le-linux/include/cudnn.h
-r--r--r-- erisuser/erisuser  38963 2017-10-20 21:28 cuda/targets/ppc64le-linux/NVIDIA_SLA_cuDNN_Support.txt
lrwxrwxrwx erisuser/erisuser      0 2017-11-17 14:24 cuda/targets/ppc64le-linux/lib/libcudnn.so -> libcudnn.so.7
lrwxrwxrwx erisuser/erisuser      0 2017-11-17 14:24 cuda/targets/ppc64le-linux/lib/libcudnn.so.7 -> libcudnn.so.7.0.5
-rwxrwxr-x erisuser/erisuser 282621088 2017-11-17 13:23 cuda/targets/ppc64le-linux/lib/libcudnn.so.7.0.5
-rw-rw-r-- erisuser/erisuser 277149668 2017-11-17 14:05 cuda/targets/ppc64le-linux/lib/libcudnn_static.a

이건 좀 묘하긴 한데, 나중에 cudnn.h를 /usr/local/cuda/targets/ppc64le-linux/lib에서 찾는 경우가 있으므로 일단 아래와 같이 soft link를 걸어 줍니다.

[root@ac922 local]# ln -s /usr/local/cuda/targets/ppc64le-linux/include/cudnn.h /usr/local/cuda/targets/ppc64le-linux/lib/cudnn.h

CUDA 설치가 끝나면, 이제 JDK와 cmake 등을 설치합니다.  이것들은 나중에 TF1.4.1을 python3 환경에서 빌드할 때 필요합니다.

[root@ac922 ~]# yum install java-1.8.0-openjdk.ppc64le java-1.8.0-openjdk-headless.ppc64le java-1.8.0-openjdk-devel.ppc64le cmake.ppc64le automake.noarch ftp libtool.ppc64le libtool-ltdl-devel.ppc64le apr-util-devel.ppc64le openssl-devel.ppc64le



이제 IBM에서 제공하는 Tensorflow Technical Preview를 설치하겠습니다.  이건 AC922을 구매한 고객에 한해서 별도로 제공되는군요.

[root@ac922 tf_tech_preview]# ls -l
total 21080
-rw-r--r--. 1 root root  5868971 Jan 11 10:02 ibm_smpi-10.02.00.00eval-rh7_20171214.ppc64le.rpm
-rw-r--r--. 1 root root   498399 Jan 11 10:02 ibm_smpi-devel-10.02.00.00eval-rh7_20171214.ppc64le.rpm
-rw-r--r--. 1 root root  4380209 Jan 11 10:02 ibm_smpi_lic_s-10.02.00eval-rh7_20171214.ppc64le.rpm
-rw-r--r--. 1 root root 10816940 Jan 11 10:02 mldl-repo-local-esp-5.0.0-20.7e4ad85.ppc64le.rpm
-rw-r--r--. 1 root root    13569 Jan 11 10:02 README.md

다음과 같이 smpi 관련 파일셋들을 먼저 설치한 뒤, mldl-repo-local을 설치합니다.

[root@ac922 tf_tech_preview]# rpm -Uvh ibm_smpi*.rpm mldl-repo-local-esp-5.0.0-20.7e4ad85.ppc64le.rpm

[root@ac922 tf_tech_preview]# yum update

[root@ac922 tf_tech_preview]# yum install power-mldl-esp


설치된  Tensorflow Technical Preview를 사용하기 위해서는 예전의 PowerAI에서처럼 *-activate를 먼저 해주어야 합니다.  단, 이젠 license 동의 과정도 있고, 또 dependency 자동 설치 과정도 있습니다.

[root@ac922 ~]# /opt/DL/license/bin/accept-powerai-license.sh   # 이걸 먼저 해주지 않으면 다음 과정이 진행되지 않습니다.

[root@ac922 ~]# /opt/DL/tensorflow/bin/install_dependencies    # 역시 이 과정을 해줘야 Tensorflow Technical Preview를 사용할 수 있습니다.
Fetching package metadata ...........
Solving package specifications: .

Package plan for installation in environment /opt/anaconda2:

The following NEW packages will be INSTALLED:

    backports.weakref: 1.0rc1-py27_0
    libprotobuf:       3.4.0-hd26fab5_0
    mock:              2.0.0-py27_0
    pbr:               1.10.0-py27_0
    protobuf:          3.4.0-py27h7448ec6_0

Proceed ([y]/n)? y

libprotobuf-3. 100% |##########################################################| Time: 0:00:00  42.42 MB/s
backports.weak 100% |##########################################################| Time: 0:00:00   9.48 MB/s
protobuf-3.4.0 100% |##########################################################| Time: 0:00:00 551.85 kB/s
pbr-1.10.0-py2 100% |##########################################################| Time: 0:00:00 286.73 kB/s
mock-2.0.0-py2 100% |##########################################################| Time: 0:00:00 249.62 kB/s

그리고나서 예전처럼 /opt/DL/tensorflow/bin/tensorflow-activate을 하면 이제 tensorflow를 사용하실 준비가 된 것입니다.

[root@ac922 ~]# source /opt/DL/tensorflow/bin/tensorflow-activate

2018년 1월 11일 목요일

ppc64le에서의 flannel 구성 : host 서버 외부로의 docker container network 구성


서로 다른 두대의 물리적 서버에 각각 위치한 docker container들끼리 network 통신을 할 수 있도록 설정하는 방법입니다.  한줄 요약하자면 여기에는 flanneld를 구성해야 하며, 이를 위해서는 먼저 etcd를 구성해야 합니다.

이 테스트에는 아래 site들을 참조했습니다.

http://docker-k8s-lab.readthedocs.io/en/latest/docker/docker-etcd.html
http://docker-k8s-lab.readthedocs.io/en/latest/docker/docker-flannel.html
http://cloudgeekz.com/1016/configure-flannel-docker-power.html
https://www.ibm.com/developerworks/community/blogs/mhhaque/entry/Docker_And_Kubernetes_Cluster_on_Power_with_RHEL7_Part_2_etcd_flanneld_daemons_on_master_node?lang=en
https://www.ibm.com/developerworks/community/blogs/mhhaque/entry/Docker_And_Kubernetes_Cluster_on_Power_with_RHEL7_Part_3_flanneld_docker_daemons_on_Docker_Container_node?lang=en

서버 환경은 IBM POWER8 Ubuntu 16.04 ppc64le이며, 두 대 서버의 hostname과 IP는 다음과 같습니다.

물리적서버 #1    sys-90725    172.29.160.221
물리적서버 #2    sys-90754    172.29.160.207


먼저 etcd를 설치합니다.  이건 flanneld 구성을 위해 필요한 일종의 key-value store입니다.  Ubuntu OS에 포함된 것을 그대로 이용하시면 됩니다.

u0017649@sys-90725:~$ sudo apt-get install etcd

설정값은 아래와 같이 /etc/default/etcd에 정리합니다.

u0017649@sys-90725:~$ sudo vi /etc/default/etcd
ETCD_NAME=sys-90725
ETCD_DATA_DIR="/var/lib/etcd/default"
ETCD_LISTEN_CLIENT_URLS="http://172.29.160.221:2379,http://127.0.0.1:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://172.29.160.221:2379"

물론 서버#2에는 거기에 맞는 hostname과 IP를 입력해야 합니다.

u0017649@sys-90754:~$ sudo vi /etc/default/etcd
ETCD_NAME=sys-90754
ETCD_DATA_DIR="/var/lib/etcd/default"
ETCD_LISTEN_CLIENT_URLS="http://172.29.160.270:2379,http://127.0.0.1:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://172.29.160.207:2379"

etcd를 start하고, 제대로 작동 중인지 확인합니다.

u0017649@sys-90725:~$ sudo systemctl enable etcd
u0017649@sys-90725:~$ sudo systemctl start etcd
u0017649@sys-90725:~$ sudo systemctl status etcd
● etcd.service - etcd - highly-available key value store
   Loaded: loaded (/lib/systemd/system/etcd.service; enabled; vendor preset: enabl
   Active: active (running) since Mon 2018-01-08 03:11:40 EST; 6min ago
     Docs: https://github.com/coreos/etcd
           man:etcd
 Main PID: 6100 (etcd)
   CGroup: /system.slice/etcd.service
           └─6100 /usr/bin/etcd

이어서, flanneld 구성 정보를 다음과 같이 json 파일로 작성합니다.  두 대의 서버에 동일한 내용으로 작성합니다.

u0017649@sys-90725:~$ vi flannel-config-vxlan.json
{
   "Network": "10.172.29.0/16",
    "SubnetLen": 24,
    "Backend": {
       "Type": "vxlan",
       "VNI": 1
    }
}

이제 이 file을 아래와 같이 etcd에 집어넣습니다.   /atomic.io/network/config은 물리적 file name도 아니고 internet 주소도 아님에 유의하세요.

u0017649@sys-90725:~$ sudo etcdctl set /atomic.io/network/config < flannel-config-vxlan.json

제대로 들어갔는지 확인은 아래와 같이 합니다.

u0017649@sys-90725:~$ sudo etcdctl get /atomic.io/network/config
{
   "Network": "10.172.29.0/16",
    "SubnetLen": 24,
    "Backend": {
       "Type": "vxlan",
       "VNI": 1
    }
}

etcd가 정상 작동 중인지는 아래와 같은 방법으로 하실 수 있습니다.

u0017649@sys-90725:~$ curl -L http://sys-90725:2379/v2/keys/atomic.io/network/config
{"action":"get","node":{"key":"/atomic.io/network/config","value":"{\n   \"Network\": \"10.172.29.0/16\",\n    \"SubnetLen\": 24,\n    \"Backend\": {\n       \"Type\": \"vxlan\",\n       \"VNI\": 1\n    }\n}\n","modifiedIndex":4,"createdIndex":4}}

u0017649@sys-90725:~$ etcdctl cluster-health
member ce2a822cea30bfca is healthy: got healthy result from http://0.0.0.0:2379
cluster is healthy


이제 flannel를 설치해야 하는데, 이건 아직 Ubuntu OS에 들어있지 않습니다.  별 수 없이 build를 해야 하는데, 여기에 버전 1.7 이상의 golang을 쓰셔야 합니다.  Default로 있는 golang 1.6을 쓰시면 error가 나니 유의하십시요.

u0017649@sys-90725:~$ sudo apt-get install linux-libc-dev golang-1.9 golang-1.9-go

u0017649@sys-90754:~$ sudo rm /usr/bin/go
u0017649@sys-90754:~$ sudo ln -s /usr/lib/go-1.9/bin/go /usr/bin/go

그냥 github의 flannel을 그대로 복제하여 build하면 역시 또 error가 납니다.  해서 다음과 같이 약간의 꼼수가 필요합니다.  즉, src/github.com/coreos라는 directory를 먼저 만들고, 그 속에 들어가서 github을 복제하십시요.

u0017649@sys-90725:~$ export GOPATH=$(pwd)
u0017649@sys-90725:~$ mkdir -p src/github.com/coreos
u0017649@sys-90725:~$ cd src/github.com/coreos
u0017649@sys-90725:~/src/github.com/coreos$ git clone https://github.com/coreos/flannel.git

이제 build 시작하기 전에, Makefile에 손을 좀 대야 합니다.  이유는 Makefile에 ppc64le도 있긴 한데 amd64를 default로 채택하게 되어 있기 때문에, 그를 ppc64le로 바꾸는 작업입니다.  우리는 여기서 make targ.gz을 할 것이니, 많은 entry 중에서 그 부분만 놔두고 #으로 막으면 됩니다.
(또는 그냥 ~/src/github.com/coreos/flannel 에 들어가서 "make dist/flanneld"만 수행해도 됩니다.  필요한 건 flanneld 뿐이거든요.)

u0017649@sys-90725:~/src/github.com/coreos$ cd flannel
u0017649@sys-90725:~/src/github.com/coreos/flannel$ export CGO_ENABLED=1

u0017649@sys-90725:~/src/github.com/coreos/flannel$ vi Makefile
# Default tag and architecture. Can be overridden
#TAG?=$(shell git describe --tags --dirty)
TAG?=v0.9.0-34-gab368026-ppc64le   # from https://quay.io/repository/coreos/flannel-git?tab=tags
#ARCH?=amd64
ARCH?=ppc64le
#GO_VERSION=1.8.3
GO_VERSION=1.9.2
...
tar.gz:
#       ARCH=ppc64le make dist/flanneld-ppc64le
#       tar --transform='flags=r;s|-ppc64le||' -zcvf dist/flannel-$(TAG)-linux-ppc64le.tar.gz -C dist flanneld-ppc64le mk-docker-opts.sh ../README.md
#       tar -tvf dist/flannel-$(TAG)-linux-ppc64le.tar.gz
#       ARCH=ppc64le make dist/flanneld.exe
#       tar --transform='flags=r;s|-ppc64le||' -zcvf dist/flannel-$(TAG)-windows-ppc64le.tar.gz -C dist flanneld.exe mk-docker-opts.sh ../README.md
#       tar -tvf dist/flannel-$(TAG)-windows-ppc64le.tar.gz
        ARCH=ppc64le make dist/flanneld-ppc64le
        tar --transform='flags=r;s|-ppc64le||' -zcvf dist/flannel-$(TAG)-linux-ppc64le.tar.gz -C dist flanneld-ppc64le mk-docker-opts.sh ../README.md
        tar -tvf dist/flannel-$(TAG)-linux-ppc64le.tar.gz
#       ARCH=arm make dist/flanneld-arm
#       tar --transform='flags=r;s|-arm||' -zcvf dist/flannel-$(TAG)-linux-arm.tar.gz -C dist flanneld-arm mk-docker-opts.sh ../README.md
#       tar -tvf dist/flannel-$(TAG)-linux-arm.tar.gz
#       ARCH=arm64 make dist/flanneld-arm64
#       tar --transform='flags=r;s|-arm64||' -zcvf dist/flannel-$(TAG)-linux-arm64.tar.gz -C dist flanneld-arm64 mk-docker-opts.sh ../README.md
#       tar -tvf dist/flannel-$(TAG)-linux-arm64.tar.gz
#       ARCH=s390x make dist/flanneld-s390x
#       tar --transform='flags=r;s|-s390x||' -zcvf dist/flannel-$(TAG)-linux-s390x.tar.gz -C dist flanneld-s390x mk-docker-opts.sh ../README.md
#       tar -tvf dist/flannel-$(TAG)-linux-s390x.tar.gz

그 다음에 make tar.gz을 합니다.

u0017649@sys-90725:~/src/github.com/coreos/flannel$ make tar.gz

오래 걸리지 않아 아래와 같이 tar.gz이 만들어집니다.

u0017649@sys-90725:~/src/github.com/coreos/flannel$ ls -l dist/*.tar.gz
-rw-rw-r-- 1 u0017649 u0017649 8179227 Jan  8 23:26 dist/flannel-v0.9.0-34-gab368026-ppc64le-linux-ppc64le.tar.gz

이걸 적절한 위치(여기서는 /usr/local/bin)에 풀어놓습니다.

u0017649@sys-90725:~/src/github.com/coreos/flannel$ cd /usr/local/bin
u0017649@sys-90725:/usr/local/bin$ sudo tar -xvf ~/src/github.com/coreos/flannel/dist/flannel-v0.9.0-34-gab368026-ppc64le-linux-ppc64le.tar.gz
flanneld
mk-docker-opts.sh
README.md

flanneld 구성에 들어가기 전에 먼저 docker daemon을 stop 시키고 docker0도 삭제합니다.

u0017649@sys-90725:~$ sudo systemctl stop docker.service
u0017649@sys-90725:~$ sudo ip link delete docker0

이제 다음과 같이 /lib/systemd/system/flanneld.service 와 /etc/default/flanneld 파일을 만들어 systemctl에 flanneld 서비스를 등록합니다.

u0017649@sys-90725:~$ sudo vi  /lib/systemd/system/flanneld.service
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service

[Service]
Type=notify
EnvironmentFile=-/etc/default/flanneld
ExecStart=/usr/local/bin/flanneld -etcd-endpoints=${FLANNEL_ETCD} -etcd-prefix=${FLANNEL_ETCD_KEY} $FLANNEL_OPTIONS
Restart=on-failure

[Install]
WantedBy=multi-user.target
RequiredBy=docker.service


u0017649@sys-90725:~$ sudo vi /etc/default/flanneld
# Flanneld configuration options
# etcd url location.  Point this to the server where etcd runs
FLANNEL_ETCD="http://172.29.160.221:2379"
# etcd config key.  This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_KEY="/atomic.io/network"
# Any additional options that you want to pass
FLANNEL_OPTIONS="-ip-masq=true"

이제 flanneld를 start 하고, 정상 작동하는지 확인합니다.

u0017649@sys-90725:~$ sudo systemctl start flanneld

u0017649@sys-90725:~$ sudo systemctl status flanneld
● flanneld.service - Flanneld overlay address etcd agent
   Loaded: loaded (/lib/systemd/system/flanneld.service; disabled; vendor preset: enabled)
   Active: active (running) since Wed 2018-01-10 20:21:19 EST; 28s ago
 Main PID: 10666 (flanneld)
    Tasks: 10
   Memory: 8.8M
      CPU: 266ms
   CGroup: /system.slice/flanneld.service
           └─10666 /usr/local/bin/flanneld -etcd-endpoints=http://172.29.160.221:2379 -etcd-prefix=/atomic.io

Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.761758   10666 main.go:238] Installing signal handl
Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.764142   10666 main.go:353] Found network config -
Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.764234   10666 vxlan.go:120] VXLAN config: VNI=1 Po
Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.830878   10666 local_manager.go:201] Found previous
Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.859766   10666 local_manager.go:220] Allocated leas
Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.860247   10666 main.go:300] Wrote subnet file to /r
Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.860273   10666 main.go:304] Running backend.
Jan 10 20:21:19 sys-90725 systemd[1]: Started Flanneld overlay address etcd agent.
Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.862149   10666 vxlan_network.go:60] watching for ne
Jan 10 20:21:19 sys-90725 flanneld[10666]: I0110 20:21:19.889547   10666 main.go:396] Waiting for 22h59m59.94

이제 보면 /run/flannel/subnet.env 이라는 파일이 생성되고 그 속에 관련 환경변수 정보가 기록된 것을 보실 수 있습니다.

u0017649@sys-90725:~$ cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.172.0.0/16
FLANNEL_SUBNET=10.172.61.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true

flannel.1이라는 interface도 새로 생성되는데, 다음과 같습니다.

u0017649@sys-90725:~$ ifconfig flannel.1
flannel.1 Link encap:Ethernet  HWaddr 66:bc:02:fe:88:b3
          inet addr:10.172.61.0  Bcast:0.0.0.0  Mask:255.255.255.255
          inet6 addr: fe80::64bc:2ff:fefe:88b3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:846 errors:0 dropped:0 overruns:0 frame:0
          TX packets:679 errors:0 dropped:8 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:77685 (77.6 KB)  TX bytes:77345 (77.3 KB)

이제 이 정보를 이용해 docker daemon의 설정값을 바꾸어 줍니다.

u0017649@sys-90725:~$ sudo vi /etc/systemd/system/multi-user.target.wants/docker.service
...
#ExecStart=/usr/bin/dockerd -H fd://
EnvironmentFile=-/run/flannel/subnet.env
ExecStart=/usr/bin/dockerd -H fd:// --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} --iptables=false --ip-masq=false

그 다음에 docker를 살립니다.

u0017649@sys-90725:~$ sudo systemctl daemon-reload
u0017649@sys-90725:~$ sudo systemctl start docker.service

이제 netstat -rn을 해보면 다음과 같이 flannel.1이라는 interface가 gateway로 뜬 것을 보실 수 있습니다.

u0017649@sys-90725:~$ netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         172.29.128.13   0.0.0.0         UG        0 0          0 ibmveth0
10.172.23.0     10.172.23.0     255.255.255.0   UG        0 0          0 flannel.1
10.172.61.0     0.0.0.0         255.255.255.0   U         0 0          0 docker0
172.29.128.0    0.0.0.0         255.255.192.0   U         0 0          0 ibmveth0


u0017649@sys-90725:~$ ip -4 a|grep inet
    inet 127.0.0.1/8 scope host lo
    inet 172.29.160.221/18 brd 172.29.191.255 scope global ibmveth0
    inet 10.172.61.0/32 scope global flannel.1
    inet 10.172.61.1/24 scope global docker0

이제 두 서버#1,#2에서 각각 docker container를 띄우고, ip address를 확인합니다.


서버 #1

u0017649@sys-90725:~$ docker run -ti --rm bsyu/caffe-ibm:v0.2 bash

root@73b40d9d2a5b:/# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:0a:ac:3d:02
          inet addr:10.172.61.2  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:950 errors:0 dropped:0 overruns:0 frame:0
          TX packets:851 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:3402207 (3.4 MB)  TX bytes:84232 (84.2 KB)


root@73b40d9d2a5b:~# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:0a:ac:3d:02
          inet addr:10.172.61.2  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:931 errors:0 dropped:0 overruns:0 frame:0
          TX packets:838 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0


서버 #2

u0017649@sys-90754:~$ docker run -ti --rm bsyu/caffe-ibm:v0.2 bash

root@bfb4da5e6b06:/# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:0a:ac:05:02
          inet addr:10.172.5.2  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:86 errors:0 dropped:0 overruns:0 frame:0
          TX packets:106 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:12926 (12.9 KB)  TX bytes:11738 (11.7 KB)


서버 #2의 container에서 서버 #1의 container로 ping을 해보고 이어서 ssh를 해보겠습니다.  (물론 서버 #1의 container에는 openssh-server 및 root login 허용 작업을 미리 해놓아야 합니다.)

root@bfb4da5e6b06:/# ping 10.172.61.2
PING 10.172.61.2 (10.172.61.2) 56(84) bytes of data.
64 bytes from 10.172.61.2: icmp_seq=1 ttl=62 time=1.01 ms
64 bytes from 10.172.61.2: icmp_seq=2 ttl=62 time=0.739 ms
^C
--- 10.172.61.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.739/0.877/1.016/0.141 ms

root@bfb4da5e6b06:/# ssh 10.172.61.2
root@10.172.61.2's password:
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-104-generic ppc64le)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Last login: Thu Jan 11 01:44:26 2018 from 10.172.5.2
root@73b40d9d2a5b:~# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 02:42:0a:ac:3d:02
          inet addr:10.172.61.2  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:1030 errors:0 dropped:0 overruns:0 frame:0
          TX packets:904 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:3410576 (3.4 MB)  TX bytes:91883 (91.8 KB)

root@73b40d9d2a5b:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
none             35G   27G  6.6G  80% /
tmpfs           2.0G     0  2.0G   0% /dev
tmpfs           2.0G     0  2.0G   0% /sys/fs/cgroup
/dev/sda2        35G   27G  6.6G  80% /etc/hosts
shm              64M     0   64M   0% /dev/shm
tmpfs           2.0G     0  2.0G   0% /sys/firmware


다 잘 되는 것을 확인하실 수 있습니다.  다음과 같이 scp에 의한 파일 전송도 잘 됩니다.

root@73b40d9d2a5b:~# echo "I love donut" > /tmp/docker1

root@73b40d9d2a5b:~# logout
Connection to 10.172.61.2 closed.

root@bfb4da5e6b06:/# scp 10.172.61.2:/tmp/docker1 /tmp
root@10.172.61.2's password:
docker1                                                                    100%   13     0.0KB/s   00:00

root@bfb4da5e6b06:/# cat /tmp/docker1
I love donut

2번 container에 traceroute를 설치한 뒤 1번 container로의 route 경로를 살펴보면 다음과 같습니다.

root@bfb4da5e6b06:/# apt-get install traceroute

root@bfb4da5e6b06:/# traceroute 10.172.61.2
traceroute to 10.172.61.2 (10.172.61.2), 30 hops max, 60 byte packets
 1  10.172.5.1 (10.172.5.1)  0.215 ms  0.030 ms  0.026 ms
 2  10.172.61.0 (10.172.61.0)  3.198 ms  3.390 ms  3.353 ms
 3  10.172.61.2 (10.172.61.2)  3.654 ms  3.926 ms  3.890 ms


즉, 먼저 서버 #2의 docker0를 통해 flannel.1으로 나가 서버 #1의 flannel.1을 거쳐 docker0로 들어가는 것입니다.

u0017649@sys-90754:~$ ip -4 a|grep inet
    inet 127.0.0.1/8 scope host lo
    inet 172.29.160.207/18 brd 172.29.191.255 scope global ibmveth0
    inet 10.172.5.0/32 scope global flannel.1
    inet 10.172.5.1/24 scope global docker0

u0017649@sys-90725:~$ ip -4 a|grep inet
    inet 127.0.0.1/8 scope host lo
    inet 172.29.160.221/18 brd 172.29.191.255 scope global ibmveth0
    inet 10.172.61.0/32 scope global flannel.1
    inet 10.172.61.1/24 scope global docker0

----------------------------------------

참고로 docker container 안에서 sshd를 살리고 root login을 허용하는 방법은 다음과 같습니다.

root@73b40d9d2a5b:/# apt-get install openssh-server

root@73b40d9d2a5b:/# vi /etc/ssh/sshd_config
#PermitRootLogin prohibit-password
PermitRootLogin yes

root@73b40d9d2a5b:/# /etc/init.d/ssh start



2018년 1월 4일 목요일

Intel processor의 보안 관련 design flaw - Intel과 AMD의 전쟁 점입가경


'더 레지스터'에서 최초로 발표한 Intel processor에 중대한 보안 결함이 있으며, 이로 인해 Windows나 Linux 등 OS에서 긴급 patch 작업 중이라고.  이 patch 적용을 하지 않으면 심각한 보안 위협에 노출되고, patch를 하면 5~30% 정도의 성능 저하가 있을 것이라고 함.  특히 filesystem I/O에도 큰 영향이 있을 것이라고 함.  사상 초유의 사태이며, 이는 x86 서버들 전체는 물론, 그를 이용한 NAS 및 storage controller, 특히 Oracle의 Exadata 등 appliance 제품들 전체에 큰 성능 저하가 예상됨.


이로 인해 밤 사이 인텔 주가는 엄청나게 떨어지다 반등하여 -3.39%로 마감. 반등의 이유는 인텔의 반박 성명 때문.

반박 성명의 내용 1줄 요약 : "우리 제품에 문제 있는 것 맞아. 그러나 우리만 있는 건 아니고 다른 processor들도 마찬가지임. 문제 해결을 위해 AMD나 MS 등 관련사들과 작업 중임."

반박 내용을 실은 기사는 아래.



반면, AMD 주가는 완전히 반대로 움직여서 엄청 솟다가 폭락하여 결국 +5.19%로 마감. 이유는 역시 저 인텔의 반박 성명 때문.

그에 대해, AMD는 다음과 같이 자기들은 문제 없다고 주장. 이 반응은 장 마감 이후에 발표된 듯.




한편, 제3자라고 할 수 있는 MS나 Amazon 등은 이 문제에 대해 'Intel, AMD, 그리고 ARM processor 등 현대적 아키텍처에 공존하는 것'이라고 일단 발표.
이번 flaw 중 Meltdown이라는 이름이 붙여진 문제는 Intel에만 존재하는 것이지만, Spectre라는 것은 AMD 등 다른 것에도 존재한다고 알려짐.

Amazon told customers of its Amazon Web Services cloud service that the vulnerability "has existed for more than 20 years in modern processor architectures like Intel, AMD, and ARM across servers, desktops, and mobile devices."