Windows 10 64bit에서 Tensorflow(텐서플로우) 설치 하기

이제 Windows 10 64bit에서 Tensorflow를 바로 설치해서 사용할 수 있게 되었다. 이전에 리눅스에서 설치 해 봤는데, 너무 귀찮고 뭔가 어려웠다. 특히 그래픽카드 설정하는 부분이 제일 짜증났다. -_- 이제는 걍 Windows 10 에 바로 설치가 되니깐.. 이번 기회에 깔아 보았다.

Python 설치

Tensorflow는 C++, Python API를 제공하고 있고, 실험적이지만 Java API 도 있다고 한다. 여기서는 Python 을 이용해서 해 볼 거다. C++ 이나 Java는 계속 컴파일도 해야 하고 귀찮아 보인다. 대부분의 예제도 Python 으로 만들어져 있으니 당근 Python 으로 가는게 좋은 수순으로 생각된다. Python은 파이썬 공식 홈페이지에서 제공하는 배포판을 설치를 해도 되지만, 머신러닝 하는 사람들은 대부분 Anaconda 라고 하는 비공식 배포판을 이용해서 설치한다. Anaconda에 있는 배포판을 설치하면 아주 많은 라이브러리를 기본적으로 포함하고 있으니. 우리도 Anaconda에 있는 배포판을 사용해서 설치 하도록 하자.

Anaconda 설치

아래의 링크에 들어 가서 Python 3.x 대 버젼을 받도록 하자. ( 예전에는 3.5 였는데, 지금은 3.6 으로 되어 있다. )

설치 방법이야, 그냥 Next 만 열심히 눌러도 잘 된다. Python 관련 PATH 설정까지 자동으로 해 주므로 잘 설치 하도록 하자.

설치시 주의 사항

Python때문인지, Tensorflow 때문인지는 몰라도, 이쪽 세계에서는 설치하는 경로에 공백이나 한글등이 들어가면 동작이 제대로 안 하는 경우가 많다. 그러므로 반드시 공백이나 한글이 없는 경로에 설치 하자. 글쓴이의 경우에는 D:\cjcho\Anaconda3 에 설치 했다.

Tensorflow 설치 하기

Tensorflow를 돌릴 수 있도록 Python은 설치 했으니 Tensorflow를 설치해 보자.

Anaconda 에서 tensorflow를 위한 가상환경 만들기

보통 개발을 하면, 환경 구성을 잘 해 두는데, 이게 이것저것 설치하다 보면 환경이 섞여서 뭔가 꼬이는 경우가 많이 발생한다. 그래서 Python에서는 "가상의 개발 환경"을 여러 프로그램별로 따로 구성해서 쓸 수 있도록 "가상환경"이라는것을 제공해 준다. 보통 virtualenv라는것을 이용해서, 환경을 여러개 만드는데, Anaconda에서는 conda 라는 명령을 이용해서 여러개의 가상환경을 만들 수 있다.

다른 개발 환경과 섞이지 않도록 tensorflow 만을 위해 독립적인 환경을 따로 만들도록 하자. conda 관련 명령을 실행 시키기 위해서 anaconda prompt를 실행 시키자. Windows 키를 누른뒤에 anaconda prompt라고 치면 나온다.

프롬프트의 앞에 (D:\cjcho\Anaconda3) 라고 뜨는것은 현재 사용중인 환경의 이름을 나타낸다.

conda info --envs 명령을 이용해서 현재 만들어진 가상 환경을 확인해 보자. 글쓴이의 경우에는 이미 만들어진 환경이 있어 아래와 같이 여러개의 환경이 나온다.

(D:\cjcho\Anaconda3) C:\Users\magic>conda info --envs
# conda environments:
#
bunnies                  D:\cjcho\Anaconda3\envs\bunnies
snowflakes               D:\cjcho\Anaconda3\envs\snowflakes
tf_gpu                   D:\cjcho\Anaconda3\envs\tf_gpu
root                  *  D:\cjcho\Anaconda3

(D:\cjcho\Anaconda3) C:\Users\magic>

Windows 10에서 동작하는 tensorflow는 python 3.5를 지원하므로 python은 3.5로 지정해서 python 환경을 먼저 만들어야 한다. 이 환경 이름을 tf 라고하자. conda create --name tf python=3.5 라는 명령을 이용하면 python 3.5를 기반으로 하는 tf라는 환경을 만들 수 있다.

(D:\cjcho\Anaconda3) C:\Users\magic>conda create --name tf python=3.5
Fetching package metadata .............
Solving package specifications: .
Package plan for installation in environment D:\cjcho\Anaconda3\envs\tf:

The following NEW packages will be INSTALLED:

    certifi:        2017.1.23-py35_0 conda-forge
    pip:            9.0.1-py35_0     conda-forge
    python:         3.5.3-1          conda-forge
    setuptools:     33.1.0-py35_0    conda-forge
    vs2015_runtime: 14.0.25420-0     conda-forge
    wheel:          0.29.0-py35_0    conda-forge

wincertstore:   0.2-py35_0       conda-forge

Proceed ([y]/n)? y

python-3.5.3-1 100% |###############################| Time: 0:00:32 545.45 kB/s
#
# To activate this environment, use:
# > activate tf
#
# To deactivate this environment, use:
# > deactivate tf
#
# * for power-users using bash, you must source
#

(D:\cjcho\Anaconda3) C:\Users\magic>

tensorflow를 동작시킬 tf 라는 Python 3.5 환경을 만들었으니, activate tf 라는 명령으로 tf 환경 안으로 들어 가자.

(D:\cjcho\Anaconda3) C:\Users\magic>activate tf

(tf) C:\Users\magic>

tf라는 환경으로 진입했다. tf라는 환경에 python 3.5가 제대로 설치 되어 있는지도 확인하고 어떤 라이브러리(?)들이 설치 되어 있는지도 확인하자. conda list라는 명령을 사용하면 된다.

(tf) C:\Users\magic>conda list
# packages in environment at D:\cjcho\Anaconda3\envs\tf:
#
certifi                   2017.1.23                py35_0    conda-forge
pip                       9.0.1                    py35_0    conda-forge
python                    3.5.3                         1    conda-forge
setuptools                33.1.0                   py35_0    conda-forge
vs2015_runtime            14.0.25420                    0    conda-forge
wheel                     0.29.0                   py35_0    conda-forge
wincertstore              0.2                      py35_0    conda-forge

(tf) C:\Users\magic>

위에 보다시피 python 3.5가 제대로 설치 된 것을 볼 수 있다.

가상환경에 tensorflow 설치 하기

tensorflow를 설치할때 CPU용을 설치 할 것인지 GPU 용을 설치 할 것인지를 정해야 한다.

가상환경에 tensorflow 설치 하기 / CPU 용

보통 anaconda에서는 conda install 이라는 명령을 통해서 패키지를 설치하게 되는데, Tensorflow 공식 가이드에서는 pip를 이용해서 설치 하도록 하고 있다. tensorflow는 CPU 버젼과 GPU 버젼이 따로 있는데, pip라는것을 이용하는 방법만이 CPU와 GPU 두가지를 모두를 제공하고 있다. conda install방식을 사용하면 CPU 버젼만 사용할 수 있다. CPU 버젼 설치는pip를 사용하지 않고 걍 conda install명령으로 설치해 볼 것이다. anaconda는 이미 tensorflow를 Windows 에서 설치 할 수 있도록 패키징 해 두었다. https://anaconda.org/ 에 접속해서 tensorflow 라고 검색을 해 보자.

  • 중요 : Tensorflow 팀에서는 Anaconda를 이용한 설치 방법에 대해서는 관라하지도 않을것이고, 확인하지도 않을 것이라고 했다. 그러므로 pip를 이용하는 방법이 더 좋겠으나, 여기서 CPU 버전은 그냥 conda 방식을 이용해서 보여 주도록 한다. 어차피 GPU 방식은 pip를 이용해서 설치해야 한다.

아래와 같이 이미 패키징 된 것들을 많이 볼 수 있다.

conda-forge가 anaconda의 기본 패키징 저장소이므로, 우리는 conda-forge / tensorflow 를 클릭해서 들어 가 보도록 하자. 그러면 아래와 같이 어떤 명령을 치면 tensorflow를 설치할 수 있는지 알 수 있다.

아까 tf환경으로 들어 가 있던 프롬프트에서 conda install -c conda-forge tensorflow=1.0.0 명령을 이용해 설치 하도록 하자.

만약 Tensorflow 공식 가이드대로 pip로 설치 하고 싶다면 pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/windows/cpu/tensorflow-1.0.0-cp35-cp35m-win_x86_64.whl 를 쳐 넣으면 된다. 혹시 이렇게 해서 설치가 안되면, 파일명의 제일 뒤를 _x86_64.whl 라고 하지 말고, _amd64.whl 이라고 바꿔보자. 얼마전까지만 해도 링크가 깨졌는지, 제대로 동작하지 않았었다.

아래 메세지들은 0.12.1 버젼을 기준으로 캡쳐 된 것이다. 그러므로 1.0.0 으로 설치를 하면 조금 다른 내용이 나올 것이다.

(tf) C:\Users\magic>conda install -c conda-forge tensorflow=0.12.1
Fetching package metadata .............

Solving package specifications: .

Package plan for installation in environment D:\cjcho\Anaconda3\envs\tf:

The following NEW packages will be INSTALLED:

    mkl:        2017.0.1-0
    mock:       2.0.0-py35_0      conda-forge
    numpy:      1.12.0-py35_0
    pbr:        1.10.0-py35_0     conda-forge
    protobuf:   3.1.0-py35_vc14_0 conda-forge [vc14]
    six:        1.10.0-py35_1     conda-forge
    tensorflow: 0.12.1-py35_2     conda-forge

zlib:       1.2.11-vc14_0     conda-forge [vc14]

Proceed ([y]/n)? y

numpy-1.12.0-p 100% |###############################| Time: 0:00:01   3.69 MB/s

tensorflow-0.1 100% |###############################| Time: 0:01:26 178.02 kB/s

(tf) C:\Users\magic>

가상환경에 tensorflow 설치 하기 / GPU 용

주의사항 : GPU용은 NVIDIA CUDA 8.0 이상을 지원하는 GPU만을 사용할 수 있다. 만약 지원하지 않는 GPU라면 이 과정을 거쳐도 사용할 수 없으니. 깔끔하게 포기하자.

아래 두 툴킷을 설치해야 한다. 이 툴킷들은 NVIDIA에서 제공하는 프로그램이고, 자신의 GPU에서 아래 버젼의 툴킷을 사용할 수 있는지 확인되어야 한다. 참고로 GTX 670의 경우 아래의 두 툴킷을 모두 사용할 수 있는 환경이었다.

NVIDIA 홈페이지에 접근해서, 가입하고... 동의한 뒤에... 다운 받아 설치해야 한다.

위 툴킷을 설치하고 하고 난 뒤 tensorflow를 설치하면 된다.

GPU 환경을 사용하기 위한 tensorflow는 conda 방식으로 설치할 수 없다.. 그러므로 pip 방식을 통해서 설치해야 한다. 아래의 명령을 이용해서 tensorflow 를 설치 할 수 있다.

pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/windows/gpu/tensorflow_gpu-1.0.0-cp35-cp35m-win_x86_64.whl 

CPU 버전을 pip로 설치할 때와 마찬가지로 해당 패키지를 찾을 수 없을때 URL의 끝 부분을 _x86_64.whl 대신 _amd64.whl로 바꿔서 해 보면 잘 될 수도 있다.

설치에는 좀 오래 걸리니깐 기다려야 한다. cuDNN 및 CUDA에 있는 몇가지 헤더 파일을 복사 하던지.. 무 그런 작업이 있다... 지금은 생각나지 않으니 통과...;; 아래 내용을 계속 진행하다 보면 문제가 생길 수 있는데, 그 상황에 맞게 인터넷에 찾아보면 어렵지 않게 문제를 해결 할 수 있다. ;; 구찬 ;;

Tensorflow가 잘 동작하는지 확인

간단 코드 확인

이하는 CPU 버젼에서 확인한 내용이다.

간단한 코드를 짜서 잘 동작하는지 확인해 보자.

(tf) C:\Users\magic>python
Python 3.5.3 | packaged by conda-forge | (default, Feb  9 2017, 15:12:38) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, Tensorflow!')
>>> sess = tf.Session()
>>> print (sess.run(hello))
b'Hello, Tensorflow!'
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print(sess.run(a+b))
42
>>> quit()

(tf) C:\Users\magic>

머신러닝 돌려서 확인하기

이 쪽 세계에는 손글씨를 인식하는 MNIST라는 유명한게 있다. 이것을 이용해서 tensorflow를 테스트 해 보자. tensorflow는 기본적인 예제(?)들을 포함하고 있는데, 간단한 명령 하나로 테스트 해 볼 수 있다. 우선 tensorflow가 어디에 설치 되어 있는지 확인하자. python -c "import os; import inspect; import tensorflow; print(os.path.dirname(inspect.getfile(tensorflow)))" 명령을 이용하면 된다. 가이드 문서에는 " 가 아니라 '로 되어 있는데, Windows에서는 ' 대신 "를 사용해야 한다.

(tf) C:\Users\magic>python -c "import os; import inspect; import tensorflow; print(os.path.dirname(inspect.getfile(tensorflow)))"
D:\cjcho\Anaconda3\envs\tf\lib\site-packages\tensorflow

(tf) C:\Users\magic>

위에 나온 경로에서 models\image\minist\ 디렉토리에 가면 convolutional.py 파일이 있다. 이게 바로 예제이다.

python -m tensorflow.models.image.mnist.convolutional 명령을 이용해서 잘 동작하는지 확인해 보자.

(tf) C:\Users\magic>python -m tensorflow.models.image.mnist.convolutional
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting data\train-images-idx3-ubyte.gz
Extracting data\train-labels-idx1-ubyte.gz
Extracting data\t10k-images-idx3-ubyte.gz
Extracting data\t10k-labels-idx1-ubyte.gz
Initialized!
Step 0 (epoch 0.00), 5.6 ms
Minibatch loss: 8.334, learning rate: 0.010000
Minibatch error: 85.9%
Validation error: 84.6%
Step 100 (epoch 0.12), 295.2 ms
Minibatch loss: 3.254, learning rate: 0.010000
Minibatch error: 6.2%
Validation error: 7.8%
....
....

시간이 꽤나 오래 걸릴것이다.

속도 차이

집에 마침 NVIDIA GPU가 있어서, CPU와 GPU를 버젼을 모두 설치해서 테스트 해 보았다.

CPU : 1590초(26분정도), Intel Core it 3570K, 3.40GHz, 4 core
GPU :  140초( 2분정도), Nvidia GTX 670

NVIDIA GTX 670이 꽤나 오래 전에 나온 GPU인데도, CPU보다 10배 가까이 빠르다.

그렇다. 이제 NVIDIA GPU를 구매하러 가자.

Facebook에서 Android dex를 압축(?) 해 주는 툴을 만들어 두었는데, 이것의 이름이 ReDex다.


https://github.com/facebook/redex


Docker로 Ubuntu 14.04 container를  만들고, 위 링크에 있는 가이드 문서대로 따라 했지만 문제가 발생했다.

몇 가지 빠진 부분이 있어 내가 했었던 작업의 기록을 남겨 둔다.

( 이 과정을 Dockerfile로 만들면 좋겠지만, 귀찮아서 통과 )



1. Ubuntu 14.04 로 Docker Container 만들기 

docker run -i -t --name ubuntu14.04_redex ubuntu:14.04 /bin/bash



2. 디렉토리 이동 ( root의 home directory에 모든것을 설치할 예정 )

cd ~



3. redex 가이드 문서에 Ubuntu 14.04 부분을 실행하기 전에 아래의 것을 먼저 실행해야 한다.

redex 설치 및 사용할 때, 그리고 인터넷에서 android sdk 를 다운로드 받을 때 필요하다.

apt-get update

apt-get install curl

apt-get install unzip

apt-get install openjdk-7-jdk

apt-get install wget



4. android sdk를 먼저 설치해야 한다. ( 아래 과정 중 test 과정에서 java를 컴파일 하고, 이를 dx로 묶는 과정이 있다. )

wget https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz 

tar zxvf android-sdk_r24.4.1-linux.tgz 

cd android-sdk-linux

tools/android update sdk --no-ui

( 이후 라이센스에 동의하라고 하면 y를 눌러 주면 된다. 혹시 화면이 멈추면 엔터를 한번 쳐 주면 라이센스 동의 문구가 나온다. )

tools/android update sdk -u -a -t 4,5

( 상황에 따라서 뒤에 있는 숫자인 4,5 를 바꿔야 하는 경우도 있다. 숫자에 맞는 version을 다운받게 된다. 목록을 알고 싶다면 tools/android list sdk -a -u 를 쳐서 번호를 확인하도록 하자. 여기서는 23.0.3을 사용한다. 24는 java version 8이 필요하기 때문에 openjdk 7으로 실행할 수 없다. )



5. ~/.bashrc 파일의 제일 아래쪽에 아래 내용을 추가하도록 하자. ( vi ~/.bashrc ) 

ANDROID_SDK=/root/android-sdk-linux/

PATH=$PATH:/root/android-sdk-linux/build-tools/23.0.3/:



6. 이후 bashrc 파일에 넣어 둔 환경을 현재 터미널에도 적용하기 위해 source 명령으로 상태를 업데이트 해 준다.

source ~/.bashrc



7. redex 가이드 문서에 따라서 각종 tool 다운로드 및 설치 ( 이하의 과정은 달라졌을 수도 있으니, 공식 홈페이지에 가이드 문서를 반드시 다시 확인하자. )

sudo apt-get install \
    g++ \
    automake \
    autoconf \
    autoconf-archive \
    libtool \
    libboost-all-dev \
    libevent-dev \
    libdouble-conversion-dev \
    libgoogle-glog-dev \
    libgflags-dev \
    liblz4-dev \
    liblzma-dev \
    libsnappy-dev \
    make \
    zlib1g-dev \
    binutils-dev \
    libjemalloc-dev \
    libssl-dev \
    libiberty-dev \
    libjsoncpp-dev



8. redex 가이드 문서에 따라서 다운로드, 빌드, 설치

git clone https://github.com/facebook/redex.git

cd redex

autoreconf -ivf && ./configure && make

sudo make install



9. 설치가 다 되었으면 잘 동작하는지 체크 한다.

./test/setup.sh

cd test

make check

근데 여기서 에러가 난다.. 이유는 모르겠음.. ;; 요건 무시해도 된다.



10. 이후 redex 명령을 이용해서 apk를 redex 시킬 수 있다.

( 만약 zipalign 문제가 생기면, 위에 설명한 환경 설정이 제대로 안 된 것이다. ./bashrc 파일에 ANDROID_SDK를 확인해 보도록 하자. )

redex a.apk -o a.redex.apk




그 결과 다음과 같은 결과를 얻었다.

c.apk -> c.redex.apk : 44.8M -> 44.5M

s.apk -> s.redex.apk : 39.8M -> 39.4M

w.apk -> w.redex.apk : 38.4M -> 38.1M

t.apk -> t.redex.apk : 33.8M -> 33.4M

원본 apk는 이미 proguard를 거친 뒤였음에도 약 250kb ~ 400kb 정도 용량이 줄어 들었다.

( 실제로 동작하는지는 확인하지 않았다 ;; ㅎㅎ )


  1. 발자국 2016.10.21 00:07 신고

    빠른나이는 아니지만 뒤늦게 프로그래밍에 재미를 찾아 공부하고있는 백수입니다.
    검색중에 들렸습니다.
    2003년부터 올해까지 꾸준히 공부하시고 포스팅 하신 흔적보고 감동받아 이렇게 덧글 작성해봅니다.
    존경합니다!!

    • 2016.12.20 12:01 신고

      오랫동안 관리되지 않던 블로그라 부끄럽습니다. 즐거운 나날들 보내세요~

자바스크립트를 공부하기로 했다.

그래서 책을 구매하려고 보니.. 제일 유명한게 "자바스크립트 완벽 가이드".

그런데.. 5e은.. 잘못 번역되어 있는게 너무 많아.. 욕을 꽤나 먹는 상황.


마침 3월 말에, 6e이 나와서.. 이 책을 구매 했다.


하지만, 여전히 몇가지 잘못 된 부분이 보여. 이곳에 정리하고자 한다.

인사이트에 올려두면 더 좋겠지만. 오랜만에 내 블로그에 글도 좀 적고..

꾸준히 공부하는 내용도 정리 좀 하고... 할 겸.


내용은 발견하는대로 귀찮지 않으면 업데이트 할 예정이다.



8페이지 중간 부분 수정


var square = function(x); { // 여기서 함수는 값이 되고, 변수 square에 할당된다.

var square = function(x) { // 여기서 함수는 값이 되고, 변수 square에 할당된다.


; 를 제거해야 한다.


9페이지 윗부분 수정


function abs(x) {    // 절대 값을 계산하는 함수를 정의한다.

    if ( x>= 0 ) {   // 괄호 안의 표현식 값이 참이면

        return x;    // if 절 안의 코드를 실행한다.

}                    // if 절의 끝을 나타낸다.

function abs(x) {    // 절대 값을 계산하는 함수를 정의한다.

    if ( x>= 0 ) {   // 괄호 안의 표현식 값이 참이면

        return x;    // if 절 안의 코드를 실행한다.

   }                 // if 절의 끝을 나타낸다


로 괄호의 위치가 잘못 되었다.


53페이지에서 String Warpper 객체 및 동작에 대한 설명 추가


var s = "test"; // 이 문자열을 사용한다.

s.len = 4;      // 문자열 프로퍼티에 값을 할당한다.

var t = s.len;  // 프로퍼티를 참조하라.


이 코드를 실행해 보면 t 값은 undefined이다. 2행은 생성된 임시 String 객체의 len프로퍼티에 4를 할당한다. 그리고 임시 객체는 바로 삭제 된다. 3행은 기존 문자열 값과 같은 값을 가진 새로운 String 객체를 생성하고 len 프로퍼티를 읽으려고 한다. 이 프로퍼티는 존재하지 않아서 undefined로 평가된다. ... 문자열이나 숫자, 불리언 값에서 프로퍼티(혹은 메서드)의 값을 읽으려고 할 때, 문자열, 숫자, 불리언 값이 객체처럼 동작하는 것을 보여준다. ... 값을 할당하는 것은 임시 객체에서 수행되며, 지속되지 않는다.


위의 문장을 이해하기 어려웠는데, 52 페이지에서 마지막에 설명된 내용과 53페이지의 마지막 내용을 잘 읽어보면 이해할 수 있다.


// javascript 에서 s 는 test라는 값을 가지는 단순한 문자열 리터럴일뿐이다.

var s = "test";


// javascript 에서 s의 프로퍼티에 접근하는 순간, s를 String 객체로 만든 뒤에 처리한다. 그 후 사용하고 난 String객체는 버린다.

s.indexOf(" ");   


// 위의 문장은 아마도 내부에서는 

// var anonymousStringObject = new String(s); 

// anonymousStringObject.indexOf(" ");

// 

// anonymousStringObject = undefined; 

// 또는 anonymousStringObject = (function () { return; })(); 로

// 처리가 될 듯 함.


// java 에서 "test" 자체가 String object이다. variable의 type역시 String class으로 받게 된다.

// java

String str = "test";


// 하지만 javascript에서는 "string"이라는 type이 따로 있고, new String(..)으로 정의할 수 있는 String object가 따로 있다.

// javascript

//

// typeof("AA") : "string"

//

// var str = new String("AA");

// typeof(str) : "object"





 63 페이지 중간 부분(3번째 단락)


+와 == 연산자는 객체를 원시 타입으로 변환할 때 Data 타입 객체는 특별하게 취급한다.

 +와 == 연산자는 객체를 원시 타입으로 변환할 때 Date 타입 객체는 특별하게 취급한다.


로 Data를 Date로 변경해야 한다.



 63 페이지 중간 부분 Date 동작이 특이한 점


javascript에서 객체타입이 원시타입으로 변환 될 때는, 기본적으로 객체에서 숫자로의 변환이다. 이 떄는 valueOf()가 사용된다. Date 객체가 참 특이하게, +와 == 연산자랑 같이 사용 할 때는 toString()이 사용되어 string type으로 변환되고, 나머지인 < 나 -(빼기) 등의 연산자랑 같이 사용 할 때는 valueOf()이 사용된다.



 66 페이지 두번째 소스 들여쓰기 잘못.


var scope = "global scope";


function checkscope() {

    var scope = "local scope";

        function nested() {

            var scope = "nested scope";

            return scope;

        }

    return nested();

}

checkscope();


var scope = "global scope";


function checkscope() {

    var scope = "local scope";

    function nested() {

        var scope = "nested scope";

        return scope;

    }

    return nested();

}

checkscope();


와 같이 들여쓰기가 잘못되었음.



 66 페이지 마지막 예제... 자바스크립트알못이지만... 설명이 애매하다... 또한, 들여쓰기도 잘못되어 있다.


function test(o) {

    var i = 0;

    if ( typeof o == "object") {

        var j = 0;

        for ( var k=0; k < 10 ; k++ ) {

            console.log(k);

        }

        console.log(k);

    }

    console.log(j);   // j는 정의되어 있고, 초기화 되어 있지 않을 것이다.

}



해당 부분은 javascript의 특징인 hoisting 을 설명하는 부분이다. hoisting이란, 변수의 정의 및 할당이 실제 코드의 순서에서 아랫쪽에 되어 있다고 하더라고, 해당 변수의 정의를 상단으로 끌어 올린것으로 처리 된다는 설명이다. 또한, javascript에서는 변수의 scope가 블록 기호인 { } 로 묶이는 부분에 대해서 scope를 가지는것이 아니라, 함수 전체에 영향을 받는것으로 되어 있다.


예제에는 j라는 변수가 if 문 안에서 정의되어 있으나, console.log(j)에서도 j의 선언부가 hoisting 되어서 접근이 가능하다는것을 표현하고 싶었던것 같은데, 그렇다면 parameter로 받는 o의 상태에 따라 j가 0이 될 수도 있고, undefined 상태일 수도 있다고 설명을 좀 더 정확하게 적었어야 했다.


hoisting 상태를 고려한다면 위의 코드는 아래와 같이 변할 것으로 예상된다.



function test(o) {

    var i = 0;

    var j;

    if ( typeof o == "object") {

        j = 0;

        for ( var k=0; k < 10 ; k++ ) {

            console.log(k);

        }

        console.log(k);

    }

    console.log(j);   // o가 object가 아닌 경우, j는 정의되어 있고, 초기화 되어 있지 않을 것이다.

}




73 페이지 첫번째 소스 코드


[?]          // 빈 배열: 대괄호 안에 표현식이 없으면 원소가 없음을 말한다.

[]        // 빈 배열 : 대괄호 안에 표현식이 없으면 원소가 없음을 말한다.


? 가 필요 없이 들어가 있다.



73 페이지 마지막 소스 코드


var p = { x:2.3, y:-1.2 };    // 두개의 프로퍼티를 가진 객체

var q = {?};                  // 프로퍼티가 없는 빈 객체

q.x = 2.3; q.y = -1.2;        // 객체 q와 p는 같은 프로퍼티를 갖는다.


var p = { x:2.3, y:-1.2 };    // 두개의 프로퍼티를 가진 객체

var q = };                  // 프로퍼티가 없는 빈 객체

q.x = 2.3; q.y = -1.2;        // 객체 q와 p는 같은 프로퍼티를 갖는다.


?가 필요 없이 들어가 있다.



83페이지 마지막 예제


1 + 2                   // => '3'

"hello" + " " + "there" // => 'hello there'

"1" + "2"               // => '12'

1 + 2                   // => 3

"hello" + " " + "there" // => 'hello there'

"1" + "2"               // => '12'


문자 3이 아니라, 숫자 3으로 계산되어야 한다.



84페이지 중간 예제


 1 + {?}     // => "1[object Object]" : 객체를 문자열로 바꾼 후 이어붙이기

 1 + {}     // => "1[object Object]" : 객체를 문자열로 바꾼 후 이어붙이기


로 필요 없이 ? 가 들어가 있다.



 94 페이지 첫번째 예제가 나온 뒤 4번째 줄에 대한 설명


또한 우변 피연산자가 함수가 아니라면 TypeError 예외가 발생한다.

일반적으로는 "함수"가 아니라, "클래스"가 아니라면 TypeError이 발생한다고 생각 할 수 있다.

하지만 javascript에서는 class라는 형태를 function으로 정의 하기 때문에, 함수가 아니라면 TypeError가 난다고 말 하는게 맞는듯 하다.



97 페이지 첫번째 예제 설명이 명확하지 않음


// max_width가 정의되어 있으면 이것을 사용한다.

// 이 외의 경우 preference 객체에 속한 값을 찾아 본다.

// 그것조차 정의되어 있지 않을 경우 하드코딩된 상수를 사용한다.

var max = max_width || preferences.max_width || 500;

 

위 설명에서 잘못된 부분이 있다.

"max_width가 정의되어 있으면 이것을 사용한다." 부분이다. 정의되어 있는것은 당연히 중요하고, max_width가 어떤 값을 가지느냐도 중요한 문제이다.

max_width가 정의되어 있지 않으면 당연히 max_width는 false로 처리 되고, 그 이후 prefrenerces.max_width를 평가할 것이다.

하지만 max_width가 정의되어 있고 0이라는 값을 가지고 있을때는 어떻게 동작할 것인가? 당연히 0은 false로 처리 될 것이고, prefrernces.max_width을 확인해야 할 것이다. 그러므로 해당 설명을 정확하게 하려면 다음고 같이 바뀌어야 한다.


// max_width가 정의되어 있으면서 0 이 아니라면, 이것을 사용한다. 정의되어 있더라도 0 이라면 이것을 사용하지 않는다.




 97 페이지 두번째 예제


function copy(o, p) {

    p = p || {?};   // 만약 인자 p가 null이면, 새롭게 객체를 생성한다.

    // ...

}


function copy(o, p) {

    p = p || {};   // 만약 인자 p가 null이면, 새롭게 객체를 생성한다.

    // ...

}


로 ? 가 쓸데 없이 들어 있다.


전반적으로 ;; 소스코드 부분의 들여쓰기나, 띄워쓰기(코딩 컨벤션)가 일정하게 되어 있지 않다. 세미콜론 처리 역시 어떤 예제는 꼬박꼬박 넣고, 어떤 예제는 두 줄이상의 소스코드인데도, 넣었다(99페이지 마지막 예제) 안 넣었다(97페이지 마지막예제) 한다. 그래서 이런건 또 왠만해서는 생략.


빈객체나 빈 문배열등을 만들때 쓸데 없이 ? 가 들어 있는 경우가 많다. ? 에 대한 문제는 너무 많아서 이제 부터는 생략.

{?} 나 [?] (?) 등을 보시게 되면... ? 는 없는 것으로 생각하고 코드를 보시라.



자바 스크립트는 기본적으로 Type Checking이라던지, 각종 코드에 대한 검사를 덜 하는것으로 판단된다. 예를 들면 변수를 선언하지 않고도 바로 사용한다던지, 읽기 전용 속성인데도 값을 할당한다던지 하는것에 대해서 에러를 발생시키지 않는다. 

이러한 방식은 코드를 더 쉽게, 그리고 유연하게 만들 수 있는 장점이 있겠지만, 나 같은 사람들에게는 오히려 혼란을 가중 시키기도 한다. 이러한 문제를 해결 하기 위해서 "strict mode"라는 것을 지원한다. 이 기능을 켜 두게 되면, 자바 스크립트가 말 그대로 "엄격"한 검사를 통해서 실행된다. 


"엄격"하게 자바스크립트를 작성하고, 실행하고 싶다면 js 파일의 첫번째 줄에 "use strict"; 를 추가해 주면 된다. 특정 함수만 "엄격"하게 실행하고 싶다면 함수 구현의 첫번째 줄에 "use strict"; 라고 넣으면 된다. ( " 를 빼 먹지 말고 다 적어야 한다. ) - IE 10 미만 버젼에서는 사용할 수 없다고 한다.



"use strict";  // 이 선언으로 인해서 현재 js 파일은 엄격 모드로 실행되게 된다.


function a() {

    // ....

}



function b() { // 아래와 같이 특정 함수만 엄격 모드로 실행되게 할 수도 있다.

    "use strict";

    // .....

}





106페이지 delete연산자 6번째줄 부터 있는 예제


var o = { x:1, y:2 };

delete o.x;

"x" in o;


뜬금 없는 문법 오류로 보일 수 있지만 in 이라는 연산자가 있는 것이다. 

"PROPERTY_NAME" in OBJECT 의 형태로 사용할 수 있다.



106페이지 중간 즈음에 delete 연산자 설명중


delete 연산자의 피연산자는 좌변값(lvalue)이다. 피연산자가 좌변 값이 아니면 연산자는 아무런 동작을 하지 않고, true를 반환한다. 피연산자가 좌변값이면 연산자는 해당 좌변 값을 삭제하려고 시도하며, 피연산자가 성공적으로 삭데되었을 경우 true를 반환한다.


좌변값이라는 용어를 먼저 알아야 한다.


변수에 값을 할달 하는 경우 아래와 같이 코드를 작성한다.


var x = 10;


위 코드에서 = 를 기준으로 왼쪽에 있는 것을 좌변값(left-value,lvalue)라고 하고, 오른쪽에 있는것 우변값(right-value,rvalue)라고 한다. variable이 좌변 값이 된다. 즉, 어떤 값을 할당 할 수 있는것들이 lvalue가 되고, 이것들을 delete 시킬 수 있다는 것이다.


설명상 "delete 연산자의 피연산자는 좌변값(lvalue)이다." 라는것은, delete의 왼쪽에 있는 값이 피연산자라는것이 아니라, delete 다음에 올 수 있는 피연산자는 lvalue 형태의 것들만 올 수 있다는 의미이다.


그 아래쪽에도 나오지만, 정확하게 말하면 위의 코드에서 x를 delete 시킬 수는 없다. delete 시킬 수 있는것은 property 형태만 가능하다. 107페이지 첫번째 예제에서 this.x 에 값을 할당 한 뒤, 그냥 x를 delete 시킬 수는 없었지만, this.x 를 delete 시킬 수는 있게 된다.


107페이지, 110페이지


부수효과


계속해서 부수효과라는 용어가 등장한다. 부수효과라는 용어는 Side Effect라는 용어의 한국어 번역 단어로 많이 사용된다. 우리가 일반적으로 생각하는 Side Effect는 "예상치 못했던 문제 상황"을 뜻하는데, 여기서는 그렇지 않다.

여기서 말하는 부수효과를 쉽게 말하면, state 를 바꾸는것을 생각하면 된다. 아래의 코드를 보자


var x = 3;


위의 코드는 사실상 아무것도 하지 않는것으로 느껴지지만, x라는 변수를 생성하고 이 변수에 3을 할당한 코드이다. x의 state가 변경된 것이다. 이렇다면 이는 "부수효과가 있다"고 볼 수 있다. 하지만 다음 코드를 보자.


Math.cos(Math.PI);


위 코드는 PI 값으로 코사인 정보를 얻어왔지만, 아무곳에서 할당하지 않았다. 즉, state의 변화가 없다. 이 경우 "부수효과가 없다." 고 볼 수 있다.



 

 



 

 



 

 



 

 


[ google drive에서 복사 해 온거라 ;;; 이미지가 깨질 수 있습니다. ]

[ 바로 보기 : https://docs.google.com/document/d/1-yNddpgu71tbFaupqrOrQ23xv8SV_6Y_8OfokPuEQTk/edit?usp=sharing ]


Windows 에서 

Docker Toolbox로 Docker 사용하기




작성자 : 조찬제 ( http://blog.ggaman.com )

작성일 : 2015년 11월 23일




Windows Docker Toolbox를 이용하여 Docker 환경 갖추기


Docker란?

 - “도커” 라고 읽음

 - Linux안에서 또 다른 Linux의 Isolate 한 환경을 만들어 줌

 - Windows에서는? VirtualBox에 boot2docker 간단한 Linux 이미지를 올리고 거기에, 또 다른 Linux를 올려 줌


Docker .vs. VM

 - VM : Linux 위에 가상화 환경을 처리한 Hypervisor가 뜨고, 그 위에 다시 Linux OS가 올라감

 - Docker : Linux 위에 Docker Engine이 있고 그 위에 OS 없이 바로 파일이 올라감. ( 속도 빠름 )

http://static1.squarespace.com/static/4ff3e918e4b03ec22b113d00/t/53cb75cae4b0cb413c8933d4/1405842891457/

Docker 이미지

 - Linux(Host OS)위에 뜰 Linux File들의 집합

 - 해당 Docker 이미지는 수정이 불가능 한 Read Only 상태이다.

 - Docker 이미지를 이용하면, 똑같은 환경의 여러 Linux를 띄울 수 있다.


Docker 컨테이너

 - Docker 이미지를 동작 시킨 Linux 상태 ( CentOS Docker 이미지의 복사본이 Ubuntu(Host OS)에 올라간 상태 )

 - 실제 동작중인 Docker 컨테이너에 접속하여 파일을 추가하거나, 삭제, 서버 실행 등을 할 수 있다.

 - Docker 컨테이너에서, Apache 서버를 띄우게 되면, 그 프로세스는 실제로는 Host OS의 자원을 사용하게 된다.

 - Docker 컨테이너가 종료되면, Docker 컨테이너에서 실행되던 모든 프로세스가 죽는다.

 - Docker 컨테이너가 종료된다고 해도, 편집된 파일들은 컨테이너에 그대로 유지 된다.

 - 종료된 Docker 컨테이너를 살릴 수도 있다. 살린 후 접속해 보면, 편집된 파일들이 유지 됨을 알 수 있다.

 - 다만, 이전에 실행되었던 모든 프로세스가 죽었으므로 다시 살려줘야 한다.

- 컨테이너가 다시 살아 날 때 기본적으로 수행해야 하는 명령어를 설정해 줄 수 있다.

- 이를 이용해 컨테이너가 뜨자마자 서버를 실행하는 등의 작업을 할 수 있다.




Windows 기준 Docker 환경 만들기 ( Mac 도 비슷할거라... )


가이드 문서 진행 기준

 - Windows 7

 - 가용 디스크 용량 50GByte 이상

Docker ToolBox

 - Docker 사용시 필요한 이것저것이 모두 묶여 있음.

 - Docker Toolbox(boot2docker, Kitematic)

 - Oracle Virtual Box

 - Git

다음의 경로에서 Docker Toolbox를 Windows용으로 다운로드 받아 설치한다.

https://www.docker.com/docker-toolbox

2015년 11월 23일 기준으로 DockerToolbox-1.9.0d.exe 다운로드를 할 수 있다.

https://thinkfree.netffice24.com/weboffice/resource/tfsi/8d13a148e467b7be3868675c3ab114b6/html/files/2080795046.png

설치 과정은 언제나처럼 OK와 Next를 연속해서 누르다가 Close 를 누르면 된다.

설치를 완료하면 아래와 같이 Quickstart Terminal 과 Kitematic을 실행할 수 있는 아이콘을 볼 수 있다.

혹시 설치를 하다가 실패하면, 시스템에 이미 설치 되어 있던, Virtual Box와 Git 등을 제거하고 다시 설치 시도해 본다.




Docker에서 사용할 VM을 만들기 전 할 일


Docker Toolbox의 제약 넘어서기

Docker를 실행할 수 있는 Terminal을 실행시키기 전에 몇가지 작업이 필요하다.

Docker를 동작시키기 위해 Docker Toolbox에서 만들어 주는 기본 VM의 Disk의 최대 용량이 약 10~18Gbyte 이기 때문에, Linux를 설치하고 HDCS등을 설치하면 용량이 부족해서 설치가 실패하는 경우가 있다. 또한 Docker용 VM Disk가 생성될 하드 디스크의 용량이 부족하면 실행시 문제가 될 수 있다.

그러므로 Docker를 동작시키기 위한 VM Disk의 위치와 용량을 변경할 필요가 있다. 여기서는 VM Disk가 생성될 하드 디스크의 위치를 "U:\_VM_\docker" 이라고 가정하고, 용량은 약 50GByte 를 잡는다고 가정하자.

Docker Toolbox 가 설치된 디렉토리로 이동해서 start.sh 파일을 문서 편집기로 수정해 준다.

https://thinkfree.netffice24.com/weboffice/resource/tfsi/8d13a148e467b7be3868675c3ab114b6/html/files/869933943.png

start.sh 파일을 문서 편집기로 열고

DOCKER_MACHINE=./docker-machine.exe

를 찾아서 아래와 같이 두 줄로 수정한다. ( Windows 지만 경로가 / 로 구분 되는것에 주의하자. )

DOCKER_MACHINE_CMD=./docker-machine.exe

DOCKER_MACHINE="./docker-machine.exe -s U:/_VM_/docker/"

또한 

if [ ! -f $DOCKER_MACHINE ] || [ ! -f "${VBOXMANAGE}" ]; then

를 찾아

if [ ! -f $DOCKER_MACHINE_CMD ] || [ ! -f "${VBOXMANAGE}" ]; then

로 수정한다.

이렇게 하면 Docker를 동작시키기 위한 VM Disk가 U:\_VM_\docker 에 disk.vmdk 파일이 생기고, 그 용량도 최대 약 50GByte까지 사용 가능해 준다. U:\_VM_\docker 디렉토리는 미리 만들어 두도록 하자.

이제 Docker 를 실행해 볼 수 있는 환경 준비가 끝났다.

https://thinkfree.netffice24.com/weboffice/resource/tfsi/8d13a148e467b7be3868675c3ab114b6/html/files/1025.png

Docker QuickStart Terminal을 실행 시키면 VirtualBox를 하나 띄우게 된다.

https://thinkfree.netffice24.com/weboffice/resource/tfsi/8d13a148e467b7be3868675c3ab114b6/html/files/1430971613.png

이후 조금 기다리면 아래와 같이 Docker Quick Terminal을 만날 수 있다. 

https://thinkfree.netffice24.com/weboffice/resource/tfsi/8d13a148e467b7be3868675c3ab114b6/html/files/567108051.png

여기서 뜨는 Linux 터미널은 사실상은 Windows 상에서 동작하는것이고, 단순히 Linux command를 사용할 수 있도록 되어 있는 터미널이다.

실제로 Docker 이미지가 올라갈 곳은 Virtual Box에 default 라는 VM에 올라 가게 된다. 궁금하다면 VirtualBox Manager UI를 띄워서 아래와 같이 확인할 수 있다.

https://thinkfree.netffice24.com/weboffice/resource/tfsi/8d13a148e467b7be3868675c3ab114b6/html/files/783967742.png

이로써 docker를 실행 시킬 수 있는 기본 환경이 마련되었다.





Docker를 이용하여 Dockerfile 로 이미지 만들기 준비



Docker 이미지를 만들기 위한 준비

여기서는 CentOS 6.6과 Java(Oracle JDK)를 설정하는 것으로 진행하겠다.

로컬 컴퓨터에 적당한 디렉토리를 만들고, 아래의 경로에 접속하여 다음의 파일을 다운로드 받자.

https://drive.google.com/folderview?id=0B4JVe12NOkhxUk41RkV5aWVRVHc&usp=sharing

 - Dockerfile ( Docker 자동 설치 스크립트 )

 - jdk-7u80-linux-x64.rpm ( Oracle JDK )

여기서는 U:\docker 라는 디렉토리에 다운로드 받았다는 가정으로 진행된다.

위 파일을 받고 나면 아래와 같이 총 2개의 파일을 다운로드 받게 된다. 



Docker 이미지 만들기


Docker Quick Terminal에서 Dockerfile이 있는 경로(u:\docker)로 이동하여 아래와 같은 명령을 내리면, Docker Image를 생성하게 된다.

docker build -t centos_oracle_java .

위 명령은 현재 디렉토리에 있는 Dockerfile 파일을 이용해서 centos_oracle_java라는 이름을 가지는 Docker Image를 생성하는 과정이다.

장비에 따라 다르겠지만, 3~5여분이 흐르면 CentOS와 Oracle Java가 설치 완료된 이미지를 생성하게 된다.

이미지가 제대로 생성되었는지 확인하기 위해 아래의 명령을 입력하여 확인하자.

docker images

centos_oracle_java는 이번에 우리가 만든 Docker 이미지이다. centos 이미지는 centos_oracle_java 이미지를 만들기 위한 기본 이미지이므로, 자동으로 받아 진 것이다. 즉, centos 이미지를 다운로드 받고, 그 이미지에다가 Oracle Java를 위한 이것 저것을 설치한 후, 그것들 다시 이미지로 만들어 둔 것이 centos_oracle_java이다. Dockerfile의 첫 번째 명령인 FROM 부분에서 centos 를 base 이미지로 사용한다고 적혀 있는 것을 발견할 수 있을 것이다.




Docker 컨테이너 만들기


이미지가 다 만들어 지고 나면, 8000 포트로 동작하는 서버를 위한 컨테이너를 만들어 보자.

docker run -i -t -p 8081:80 --name chat_server centos_oracle_java //bin/bash

위 명령은 centos_oracle_java 이미지를 이용하여 chat_server라는 이름을 가지는 컨테이너를 하나 만들게 된다.

chat_server 라는 이름을 가진 컨테이너에서 8081 포트를 Host OS에서 공개한 채로 서버가 뜰 것을이므로,  컨테이너 외부에서 접속할 포트컨테이너 내부 포트로 80을 연결하도록 설정하였다. 그러므로 컨테이너에 들어갈 프로그램을 작성 할 때엔 컨테이너 내부 포트인 80 포트를 기준으로 작성해야 한다.

컨테이너가 동작하고 난 직후에 자동으로 //bin/bash 명령이 수행되어 컨테이너 안에 shell로 접속할 수 있게 된다. ( 원래는 /bin/sh 처럼 제일 앞에 / 를 한개만 적어야 하나, Winodws에서 수행할 때에는 제일 앞에 / 를 두개 적어 줘야 한다. ) 컨테이너 안의 Shell로 잘 들어왔는지 확인하기 위해서 아래 명령을 쳐서 확인해 보도록 하자. Cent OS 정보를 볼 수 있을 것이다.

cat /etc/*release*

이제 컨테이너를 빠져 나오도록 하자.

exit

컨테이너에서 빠져 나오면 다시 Docker Quick Terminal 로 돌아 온 것을 알 수 있다.



Docker 컨테이너 상태 확인하기


docker 컨테이너 목록을 보고 싶다면 다음의 명령어로 확인 할 수 있다.

docker ps -a

출력은 다음을 뜻한다.

 - 컨테이너 ID는 9d77b23c2910 이다. 

 - 컨테이너는 centos_oracle_java라는 이미지를 바탕으로 생성된 것이다.

 - 컨테이너가 뜰 때 수행된 명령은 //bin/bash 이다.

 - 컨테이너가 만들어 진지 7분 정도 지났다.

 - 컨테이너가 2분전에 종료되었다.

 - 현재 할당된 포트는 없다.

 - 컨테이너 ID가 너무 어려워서  우리가 chat_server 라는 이름을 주었다.

우리가 이전에 아래와 같은 명령을 내려서 Docker 컨테이너를 띄웠다.

docker run -d -p 8081:80 --name chat_server centos_oracle_java //bin/bash

하지만, 현재 docker 컨테이너의 상태를 확인해 본 결과 port 할당이 하나도 이루어져 있다는것을 알 수 있다. 이는 docker 컨테이너가 내려 갔기 때문에 더 이상 Host OS의 port를 mapping 하지 않게 되었기 때문에 없는 것이다.



Docker 컨테이너 살리기/죽이기/없애기

죽었던 chat_server 컨테이너를 살려 보도록 하자.

docker start chat_server

이후 docker ps -a 를 통해서 chat_server 컨테이너가 동작 중인지 확인해 보자.

그 결과 STATUS 부분에서 “Up” 이라고 적혀 있으면 컨테이너가 실행 중인 것이다.

하지만, 이상하게도 이전과는 달리 chat_server 컨테이너에 shell로 들어 간 것이 아니고, Docker Quick Terminal로 빠져 나와 있다. 또한, 빠져 나와 있는데도 chat_server 컨테이너가 죽지 않고 살아 있다는것을 알 수 있다.

여기에 대한 설명은 어려운데, 간단히 설명하면, 컨테이너는 실행 할 때 수행한 명령의 process가 종료되지 않으면 컨테이너를 살려두고, process가 종료되면 컨테이너도 같이 종료시키게 된다. 우리가 chat_server를 실행시킬 때 내부적으로 //bin/bash를 실행 시키고, 그냥 나왔기 때문에 컨테이너 안에서는 여전히 //bin/bash process가 살아 있어서 컨테이너가 종료되지 않고 살아 있는 것이다.

만약 컨테이너를 죽이고 싶다면 아래의 명령을 이용할 수 있다.

docker stop chat_server

그렇다면 컨테이너를 띄운 상태에서 shell로 접근하고 싶을때는 어떻게 해야 할까? 두가지 방법이 있다.

  1. 새로운 컨테이너를 만들면서 shell로 접속하기

  2. 이미 만들어진  컨테이너에 shell로 접속하기

    1. 만들어져는 있지만 죽은 컨테이너를 띄우면서 shell로 접속하기

    2. 이미 띄워진 컨테이너에 shell로 접속하기

1의 방법인 컨테이너를 띄우면서 shell로 접속하기는 이전에 chat_server 컨테이너를 띄울 때 사용했던 방법과 동일하다.

docker run -i -t -p 8081:80 --name chat_server centos_oracle_java //bin/bash

2.a의 방법은, 우선 chat_server 컨테이너를 띄운 뒤에 2.b 방식을 따라하면 된다.

docker start chat_server

2.b 방식은, 이미 떠 있는 chat_sever 컨테이너에 명령을 수행하고, 그 명령의 입력과 출력을 주고 받을 수 있도록 설정하면 된다. 아래의 명령으로 shell에 접속 할 수 있게 된다.

docker exec -i -t chat_server //bin/bash

-i 과 -t 옵션을 주어야만 //bin/bash 명령을 컨테이너와 주고 받을 수 있다.

chat_server 컨테이너가 더 이상 필요 없다면 삭제를 하면 된다. 만약 삭제하고자 하는 컨테이너가 실행중이라면 먼저 docker stop 으로 멈추고 아래 명령을 이용하면 삭제 할 수 있다.

docker rm chat_server

다시, centos_oracle_java 이미지에서 chat_server2 라는 컨테이너를 만들면, 완전 clean 한 상태로 새로운 컨테이너를 만들 수 있다. 만약 chat_server 에 이것저것 작업하다가 환경이 잘 못 된 경우, 이런 방식으로 쉽게 clean 한 환경을 만들 수 있는 장점이 있다.

새로운 chat_server2 컨테이너를 만들고 shell로 접근해 보자. 아래의 명령을 이용하도록 하자.

docker run -i -t -p 8081:80 --name chat_server2 centos_oracle_java //bin/bash

컨테이너의 shell에 접근한 상태에서 exit 명령으로 shell을 종료하게 되면, 컨테이너 역시 종료 된다. 그렇다면 컨테이너를 종료 시키지 않은 상태에서, Docker Quick Terminal로 나갈려면 어떻게 해야 할까? 아래의 키 조합을 순차적으로 누르면 된다.

^P ^Q ( Control + P, Control + Q )

 

docker ps -a 명령으로 확인해 보면 chat_server2가 종료되지 않고 실행 중인 것으로 발견할 수 있다.



Docker Toolbox 지우기


0. VirtualBox 에 떠 있는 모든 VM 들 내리기

1. 제어판 -> 프로그램 제거 -> Oracle VirtualBox ( Virtual Box를 사용한다면 그냥 둬도 된다. )

2. 제어판 -> 프로그램 제거 -> Docker Tool box

3. 제어판 -> 프로그램 제거 -> Git ( Git 을 사용한다면 그냥 둬도 된다. )

3. c:\Users\사용자명\.boot2docker 삭제

4. c:\Users\사용자명\.docker 삭제



  1. 2018.01.16 02:51

    비밀댓글입니다

아두이노 IDE를 사용해 보면 알겠지만, 한글에 대한 처리가 잘 되지 않는다.


한글 글자 조합이 완료되었을때에 대한 처리부분을 대충 수정해서

사용하는데 크게 무리가 없도록 처리 해 두었다.

( 물론 아직도 버그는 있고, 그걸 굳이 고칠 생각은 없다. )


첨부된 pde.jar 파일을 다운로드 받아

arduino-1.0.5-r2/lib 밑에 pde.jar 을 교체해 주면 된다.



필요하신 분들은 잘 쓰시길...


pde.jar


'공부 > 기타' 카테고리의 다른 글

[아두이노] Arduino IDE 1.0.5-r2 한글 패치  (2) 2014.03.08
발해고에 대하여...  (0) 2004.10.25
  1. CRX48 2015.03.20 17:21 신고

    감사합니다~

백만년 만에 글. 너무 글을 안써서 오랜만에 생각나서 써 봄. ㅋ


Java에서 제공하는 기본적인 Reader계열에서는 UTF-8의 BOM을 제대로 처리하지 못합니다. 그렇기 때문에 BOM이 있는 UTF-8 stream을 Reader로 넣으면, String의 제일 앞글자에 0xfeff 가 들어 오는 문제가 생깁니다.


"UTF-8의 BOM을 제대로 처리 못하는 Java의 문제가 아니냐?" 고 물을 수 있겠지만은, Unicode 표준에는 UTF-8에 대해서는 BOM을 적지 않도록 권고(neither required nor recommended)하고 있습니다. 그런데 MS Windows 계열에서 만들어진 일부 문서에서는 BOM을 포함하는 경우가 종종있습니다.


이를 해결할 수 있는 방법은, 


 1. BOM에 대한 정보를 inputStream에서 미리 읽어 버리고, BOM 이후부터 Reader에서 읽도록 처리하는 방법

 2. 얻어진 String에서 tmp = tmp.replace("\uFEFF", ""); 와 같은 방법으로 0xfeff 무시하기

 3. 각종 외부 라이브러리를 이용해서 처리 하기


입니다.


  1. 제미니 2014.07.08 13:41 신고

    이 글 덕분에 문제를 해결했습니다. 감사합니다!

Google Android 개발자 간담회에 참석을 했다.


일시 : 2012년 9월 17일.

장소 : 강남 파이낸스 센터 21층 (구글코리아)



주요 내용은 아래와 같았다.


* Android Design Guide

* What's New in Android

* In App Billing / Subscription

* How to get featured in Play Store

* QnA


해당 세션들은 외국분들이 와서 영어로 진행하였다. - 정말 다국적 발표자들이었음.


기본적인 내용은 Google I/O 2012 행사에서 진행했던 세션들을 정리해서 다시 이야기하는 형식이었다.

( 유튜브에 가면 Google I/O 2012 행사를 모두 볼 수 있다! - 보러가기 )


나는 운 좋게도 Google I/O 2012에 직접 참석을 했었고, 회사에서 Google I/O 행사 발표 준비를 하느라 많이 본 내용이었기 때문에 몇몇 세션들은 어렵지 않았다.


그 중에서 내가 참석하지도, 유튜브에서 보지도 않았던 "In App Billing/Subscription" 관련 세션에서 재미나는 것을 알게 되었다. 이미 알고 있는 사람들은 뻔할 수도 있지만 말이다. Google Play 스토어에서 물건을 구매하면 총 금액의 30%를 구글측에서 가지고 가고, 나머지를 개발자가 가지고 간다고 알고 있었다.


(확대해서 사진을 찍었더니. 엉망이네 T_T )


하지만 정확하게 말하면 그 30%를 

텔레콤회사(통신사)

빌링회사(카드사)

구글

욜케 3군데서 나눠 먹는다고 한다. 어찌보면 당연한건데, 난 그냥 자연스럽게 구글이 다 먹는다고 생각하고 있었다.


나온 이야기중 몇가지 정리를 하자면.

1. 메뉴를 아랫쪽에 배치하지 말자.

허니컴과 ICS에서는 기본적으로는 하드웨어 버튼이 없으며, 스크린의 하단에 back, home 등의 버튼이 존재한다. 그러므로 App의 메뉴나 버튼이 하단에 존재하면 사용자가 잘못 누르게 될 가능성이 있다. 그러므로 하단에 버튼이나 메뉴를 배치하지 않도록 하자.


2. billing 시스템은 섞어 쓰지 못한다.

그러니깐 삼성AppStore에 올리면서 Google Billing system을 사용하지는 못한다. 만약에 삼성앱스와 구글플레이에 모두 올려야 한다면 삼성앱스에 올릴때는 삼성의 결재 시스템을, 구글 플레이에 올릴때는 구글플레이의 결재 시스템을 사용하는 두개의 apk을 각각 올려라.


3. 애플의 앱스토어에 있는 리딤코드 같은건 아직...(뒤에 앉아서 제대로 못 들어서 맞는지는 모르겠다. )


4. 구글 플레이에 나라별로 다른 스크린샷을 올릴 수 있을까? 없다.


5. 디벨로퍼 콘솔의 beta가 진행중( 난 안 들어가봐서 잘 모르겠네 ;; )


나머지는 I/O 2012 자료를 참고하는것이 좋겠다. ( 굳이 여기에 정리 안해도 찾아 볼 사람들은... ㅎㅎ )


생각보다 사람들이 질문을 많이 했다. 나도 궁금한게 한 3개쯤 됐는데 못 물어보고 말았다능.. 쩝.


그리고 한국말로 질문한 사람은 나 밖이다. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

영어 공부를 해야 겠다고 느끼긴 했으나, 영어로 질문을 못했다고 부끄럽거나 하지는 않다. ㅋㅋ

( 그래도 영어 공부는 정말로 해야 겠다. -_- 질문은 커녕 말을 알아 먹기도 힘드니 T_T )


재미난 것은 한국말로 질문을 했는데도, 통역을 통하지 않고도 내 질문을 알아 먹었다는것!!!

"Google Plus App이나 Youtube App에서는 Home Button을 누르면 Menu가 왼쪽에서 나오는데, 이렇게 Menu가 나오는 방식이...." 이라고 한국말로 물었는데 -_- 단박에 알아 들었다는게... 하긴 한국말 절반에 영어 절반이니... ㅎㅎ


이런 행사가 있을때마다 회사의 파트장님이나 팀장님에게 허락을 받아야 하는데(업무시간이 마치지 않은 시간이니깐 허락을 얻는건 당연) 매번 참석하도록 해 주셔서 감사합니다.(라고 뜬금 없는 아부를 좀... ) 


이런 행사에 참석을 하면서 느끼는건데, 무언가 목적을 가지고 참석하는 사람들은 부끄러움은 살짝 접고 참석하기 때문에 뭔가 더 활발한 모습을 볼 수 있는것 같다. QnA 시간에도 열의를 가지고 참석하고, 옆 사람에게 말도 쉽게 걸고. 그래서 보고 있으면 참 흐뭇하다. ㅎㅎ




질문에 대한 이야기가 나왔으니 잠시 다른길로 빠져서 예전부터 가지고 있던 생각을...

( 이걸로 다시 글을 하나 쓰자니... 좀 귀찮기도 하고 말야. ㅎㅎ )


가끔씩 세미나에 참석을 하면 이상한 버릇을 가지고 있는 사람들을 만날 수 있다. ( 이번 구글 세미나는 아니었으니 괜히 이번에 참석하신 분들은  신경쓰지 않아도 된다. )


세미나를 진행하면 어떤 수준의 사람들이 참석을 하는지 알 수 없고, 그렇기 때문에 세미나 발표자료를 만들 때 되도록이면 쉽게 만들기 위해서 노력을 하고, 그렇게 때문에 "정확하지 않은 내용"을 발표에 포함시키는 경우도 있다. 


그리고 나중에 질문의 시간에 "니가 뭘 모르는가 본데..." 라는 늬앙스를 잔뜩 풍기면서 질문을 던지는 사람들이 있다. 이런건 발표하는 사람에 대한 예의가 아니라고 생각된다. 소위 말하는 "우리끼리 하는 클래스명까지 나오는 디테일한 기술 세미나"도 아니고, 많은 사람들을 위한 공개 세미나에서 발표하는 건데... 설령 그 사람이 정말로 잘못 알고 있거나, 혹은 모른다고 해도 그런식으로 말을 해야 할까?


그 사람은 그 세미나를 준비하기 위해서 많은 준비를 했을 것이다. 실제 발표 내용을 조사하고, 발표내용을 다듬고, 실제 발표 연습을 해는것만으로 2-3일은 소비했을 것이다.

그런 사람들을 보면

"그럼 니가 해 보던가, 안 할 꺼면 닥치고 있어!" 

라고 외쳐 주고 싶다.



누군가가 이런류의 이야기를 했다. ( 잘 기억은 안 난다. )


"서로 잡아 먹기 위한게 아니라고"

"아무런 도움이 되지 않는다고"

"해결해 나가기 위한 것이라고"





암튼!

주저리 주저리 끝. ㅋ.



Google Android 개발자 간담회 덕분에 백만년만에 블로그에 포스팅 해 봄.

  1. 돼지왕왕돼지 2012.10.14 10:45 신고

    구글 아이오도 직접 다녀오셨어요? 좋으시겠어요 부럽부럽 ㅠㅠ

    • 2012.10.14 16:59 신고

      오잉~
      제가 언젠가 방문해서 댓글까지 남겼던
      돼지왕왕돼지 님이시다 ㅎㅎ

      완전 좋더라구요.
      내년엔 자비를 들여서라도 가볼려구요 ㅎㅎ

      방문 감사합니다 ㅎㅎ

안드로이드의 타겟은 모바일 환경이기 때문에, 프로그램을 만들거나 실행할때 몇몇 제약이 있다.

이야기 할 내용은 왠만해서는 접할 수 없는 안드로이드 프로그램의 메소드 갯수 제한에 관한 이야기다.

안드로이드 프로그램을 작성하기 위한 순서를 보자.

1. "자바언어"로 프로그램을 작성한다.
2. "자바 컴파일러"로 JavaVM의 Bytecode를 생성해 낸다. 
3. JavaVM의 Bytecode를 DalvikVM의 Bytecode로 변경하면서
4. .dex 파일을 만들어 낸다.
5. .dex 파일과 xml 파일과 각종 이미지들을 zip포맷으로 묶고, 확장자를 apk로 바꾼다.
( 5번 항목은 더 복잡한 내용이 있지만 여기서는 굳이 말할 필요가 없어서 대충. ㅋ )


안드로이드에서는 많은 class 및 jar들도 모두 한꺼번에 묶어서 .dex 파일로 묶어 주게 되어 있는데, 안드로이드 프로그램 배포 파일인  .apk 파일을  .zip 으로 확장자를 변경한 뒤에 압축을 풀어 보면 classes.dex 파일을 볼 수 있는데, 이것이 바로 DalvikVM의 Bytecode가 들어 있는 .dex 파일이다. 모든 class 파일과 jar 파일을 단 1개의 .dex 파일안에 다 넣게 되어 있다. ( 틀렸다면 제보해 주세요. )

이때, 발생 할 수 있는 문제가 바로 메소드 갯수 제한이다.

큰 프로그램을 작성하다 보면, 혹은 많은 양의 라이브러리를 가져다 쓰다 보면 당연히 프로그램의 덩치가 커지게 될 것이다. 이때 빌드를 돌리게 되면 위의  순서에서 2번 class파일이나 jar파일을 만드는데는 문제가 없으나, 3번 과정에서 dex 파일을 만들때 "format == null" 따위의 도저히 예측 할 수 없는 에러를 발생 시키고 죽어 버린다.

모바일프로그램이라 큰 프로그램을 짜지 않을것이라고 생각했는지, 아니면 가난한 리소스때문에 일부러 그렇게 설계했는지 몰라도 dex 파일에는 64k(6.5만개) 이상의  메소드가 정의 될 수 없도록 되어 있다. dex 파일 포맷에서 method index를 저장하는 공간이 16bit로 되어 있으므로 당연히 6.5만개 이상의 메소드를 만들게 되면, method index table의 공간이 부족하여 dex 파일을 못 만드는 것이다.

혹시나 6.5만개 이상의 메소드를 사용하는 프로그램을 만들게 되면 거기에 대한 대비책을 만들어야 한다.

1. 안드로이드에서 기본적으로 제공하는 라이브러리를 쓰자.
2. 프로그램 빌드시 실제로 사용되지 않는 라이브러리들을 제거 하자.
3. 필요 없는 메소드들을 생성하지 말자.
4. 그렇게 큰 프로그램은 모바일 프로그램으로 만들 생각을 하지 말자.


하지만, 프로그램에서 필요 없는 메소드들이 어디 있으랴? 좀 더 구조적이고 아름다운 코드를 짜기 위해서 메소드 갯수가 늘어 나는것은 어쩔 수 없는 일이다. 그러므로 좀 더 우아한 방법을 찾아야 하고, 그 방법이 바로 바로 ProGuard 이다.

ProGuard는 Java Bytecode를 난독화, 사용하지 않는 코드 제거, 최적화 등을 수행해 주는 오픈소스 툴이다. 구글 안드로이드측에서도  2.2 인가 부터 이 놈을 추천하고 있다. 해당 툴을 사용하여 최적화 및 사용하지 않는 코드를 제거하게 되면, 메소드 갯수가 많이 줄어 든다. 단, 최적화를 거쳤다면 메소드가 사라지기도 하고, com.ggaman.A.java 파일의 내용 및 메소드가 com.ggaman.B.java 으로 이동되어 있는 경우도 있다. 
그러므로 실제 출시된 제품의 디버깅이 힘든 점이 존재한다. 물론 옮겨진 위치나 변경된 정보를 로그로 남겨주지만 그거 비교하는 것도 얼마나 짜증나는 일이겠는가? 또한 ProGuard 역시 사람이 많든 프로그램이라 버그가 있어, 제대로 빌드를 만들어 주지 못하거나, 빌드는 되나 실행시 제대로 수행되지 않는 경우도 있다. 

하지만 6.5만개 이상의 메소드를 사용할 수 밖에 없는 경우에는 어쩔 수 없이 선택해야만 한다. 

ProGuard에 대한 설명을 하기 위해서 글을 적은것이 아니기 때문에  ProGuard에 관련된 더 자세한 사항은 아래 링크를 이용해 주시라.

구글의 ProGuard 검색 결과
http://www.google.co.kr/#q=proguard&newwindow=1



또 다른 방법도 있다. 문제 상황에 대해서 한번 더 생각해 보면 프로그램의 덩치가 크기 때문에 dex 파일을 만들때 메소드 갯수가 많아서 dex 파일을 못 만들어 내는 것이다. 그렇다면 dex 파일을 여러개 만들면 안될까?

몇 일 전 안드로이드 개발자 블로그에 이 문제를 해결 할 만한 방법이 올라 왔다.

dex 파일을 쪼개서 만들고, Custom Class Loader를 이용해서 dex 파일에 있는  class를 사용하는 방법이다. Android에서는 dex 파일을 읽기 위해서 DexClassLoader를 제공해 주고 있다. 이를 이용해서 파일로 저장되어 있는 dex파일세서 class를 읽어와서 사용할 수 있음을 보여준 예제이다.

다만 해당 방법은 항상 dex파일을 로컬 스토리지에 두고 사용해야 하므로 최초 수행시 dex파일을 로컬 스토리지로 복사해야 하는 점, 그리고 자바의 리플렉션을 이용해서 Class를 찾고 객체는 생성해주어야 하기 때문에 동작이 느린 이슈가 있을 수 있다. 

하지만 로컬스토리지 복사나 동작이 느린것것이 프로그램이 아예 빌드가 되지 않는 것 보다는 훨씬 더 좋은 선택으로 생각된다.

해당 블로그 글은 아래의 링크를 클릭해서 따라 가면 된다.



오랜만에 포스팅 끝. ㅋ.
(검색이 잘 되도록 제목 수정. ㅋ )
  1. 닉쑤 2011.08.03 03:23 신고

    저도 안드로이드 폰 씁니다 ㅎㅎㅎ

    하지만 개발 내용은 알고싶지 않은..ㅎㄷㄷ;

+ Recent posts