DLib는 machine learning algorithms 을 가지고 있는 툴킷이다. (http://dlib.net/ ) 이 자체는 CPP 라이브러리이나 파이썬으로 해당 라이브러리를 이용할 수 있다. 기본적으로 많은 기능이 제공되는데 이 중, 내가 가장 흥미를 느낀 기능은 face landmark 추출 기능이다. face landmark 는 얼굴의 특정지점을 추출하는 기능이다. DLib 가 기본적으로 제공하는 기능은 눈썹, 눈, 코, 입, 얼굴 아래형태이다. 해당 라이브러를 이용하면




이 처럼 얼굴의 위치를 잡아준다. 물론 오차는 약간 있다. 직접 학습을 하게 만들 수 있지만 학습데이터를 만드는 것도 많은 작업이 필요한지라 기존 데이터를 이용하는게 더 편하다. 



해당 라이브러리를 이용해 특정 지점에 스티커를 놓는 기능을 만들어 보았다. https://github.com/yiunsr/imglst 에서 소스를 확인 할 수 있고  http://imglst.labstoo.com/demo/landmark 에서 테스트 해 볼 수 있다. 기능이 라는게 별거 없는데, 얼굴 추출 기능은 http://dlib.net/face_landmark_detection.py.html 에 있는 기능을 이용했다. 이 기능은 원래 비디오 인데 적당히 사진을 이용할 수 있도록 수정했다. 


 대부분은 작업은 HTML5 Canvas 작업들이 더 힘들었다. dlib 는 이미지 위치만 잡아 주지 저렇게 점 까지 찍어 주지 못한다. 점까지 찍어 주고 숫자 출력하는게 더 힘들었다. 


 

 이 이외에 face morhping(http://imglst.labstoo.com/demo/morhping) 하는 기능도 샘플로 넣었다. 이 기능은 (https://github.com/alyssaq/face_morpher ) 의 기능을 이용했다. 두 얼굴을 합쳐서 중간 얼굴을 만드는 기능이다. 결과적으로 하고 싶은 것은 저 중간 얼굴을 실제 사진에 넣는 것이다. ( https://www.learnopencv.com/face-swap-using-opencv-c-python/ 이 기능 처럼 face swap 을 잘 적용하면 될 것 같은 느낌이다. ). 이 부분은 좀 더 공부가 필요할 것 같다. 

 

아래 세팅 설정들은 AWS EC2, Virtualbox 내 우분투 설치, conoha(https://www.conoha.jp/ko/ ) 를 설정하면서 사용된 설정들이라, 어떤 경우, 맞지 않을 수 있다는 것을 주의하자. 그리고 내가 의식적으로 하는 작업이나 패키지 설치들이 있기 때문에 필수 적이지 않는 것도 꽤 많다. 

(그런데 다 같은 Ubuntu 16.04 버전인데 조금씩 차이가 나는지 모르겠다. 아무래도 호스팅업체에서 제공하는 버전 자신들 서버에 맞게 조금씩 수정을 거친 것 같은 느낌이다. ) 


설정을 하는 경우 여러가지 설정파일을 생성하게 된다. 간혹 하나의 서버에 여러 프로젝트 서비스를 돌리는 경우가 있을 수 있기 때문에(나는 특히 이런 경우가 참 많았다. ) 가능한 한, 프로젝트 명에 맞추어 ini,  pid , sock 파일 또는 리소스를 생성하는게 좋다. 내 경우에는 같은 프로젝트로 test 서버, 스테이징서버 같은 것을 한 서버에 운영하는 경우, 프로젝트명_test,  프로젝트명_staging 이런 식으로 구별해서 이름을 정하는 편이다. 그리고 내가 사용한 파일이름이나 리소스이름은 임의적인 것이므로 원하는 대로 변경할 수 있다. 


1. 시간설정


1-1. timezone 설정


콘솔에 date 를 치면 시간 뒤에 붙는 세자리의 영문자를 통해서 timezone 을 알 수 있다. 

timezone 설정은 서비스에 따라서 크게 뭘로 해도 문제가 안될 수도 있고 될 수도 있는 부분이라 본인의 서비스에 맞게 잘 설정해야 한다. 그리고 서비스와 관련이 없더라도 로그 볼 때의 기준이 되는지라 팀이나 관리를 하는 나라를 고려 할 필요가 있다. 

 내가 했던 서비스의 경우 django setting 의 timezone 에 의해 동작하는 경우가 많은 지라 이 서버 timezone이 크게 중요하지는 않았다. 그래서 그냥 Asia/Seoul 로 설정하는 편이다.


sudo timedatectl set-timezone Asia/Seoul 

단순히 timezone 리스트를 확인 하고 싶은 경우

timedatectl list-timezones

로 확인 하면 된다. 

1-2. 주기적으로 시간 서버로 부터 시간을 맞추도록 설정
그리고 컴퓨터 시간일지라도 조금씩 오차가 발생하기 마련이다.  이 오차가 쌓이면 꽤 큰 차이의 시간 차가 생긴다. 어떤 서비스의 경우 시간차이 때문에 오류가 생길 수 있다. 그리고 관리하는 서버들 간의 시간이 차이가 발생하면 오류를 분석하기 어려워질 수도 있고, 오류도 발생할 수도 있다. 

그래서 정확한 시간을 알고 있는 다른 서버로 부터 시간을 받아올 수 있도록 설정이 필요하다. 

ntp(네트워크 타임 프로토콜) 라는 서비스가 돌아가는지 확인 해 보자.

ps -ef | grep ntpd 


결과

ntp       9154     1  0  2017 ?        00:07:10 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 111:117

root     11308 11188  0 00:16 pts/0    00:00:00 grep --color=auto ntpd


위 명령어를 입력했을 때,  결과가 2줄이 나온다면 걱정하지 말고 다음 내용은 무시하자.

 grep 이 부분의 결과만 나온다면 ntp 서비스가 나온느 것이 아니라서 주기적으로 시간을 맞출 수 있도록 설정이 필요하다. 


sudo service ntp start 

를 이용해서 서비스를 돌린다. 


AWS 의 경우 아래 링크를 참고해서 더 정확한 시간 설정을 하는 것을 추천한다.
https://aws.amazon.com/ko/blogs/korea/keeping-time-with-amazon-time-sync-service/

이 방법이 사용되지 않는다면 단발성으로 
sudo rdate -s time.bora.net
을 이용할 수 있다. (time.bora.net 은 많이 사용하는 서버이다.

이 방법을 crontab 을 이용해서 밤 12시에 하루에 1번 주기적으로 실행시키는 방법도 있다.


2. 기본적인 패키지 설치
리눅스를 사용하다보면 컴파일해서 설치할 일이 많다. 내가 직접 컴파일(빌드)을 하지 않더라도 진행과정에 컴파일(빌드)하는 동작이 들어가는 경우가 많다. 그래서 기본적인 개발환경을 세팅할 필요가 있다. 이 때를 위해 build-essential  를 설치한다.  pip install 하는 경우 꽤 많은 경우 자동으로 컴파일 해서 설치하는 경우가 많으니 필수이다. 

리눅스에서 뭐뭐뭐 -dev 형태로 된 패키지를 설치하는 경우가 있다. 이 경우는 라이브러리 인 경우가 많다. ( https://stackoverflow.com/questions/1157192/what-do-the-dev-packages-in-the-linux-package-repositories-actually-contain ). 어째든 뭔가 빌드해서 설치하는 경우가 사용된다. 간혹 이러한 dev 패키지가 설치되지 않으면 빌드하다 무슨무슨 .h 파일이 없다고 하면서 에러가 뜨는 경우가 발생한다. 


# 기본적인 빌드 환경 제공

sudo apt-get -y install build-essential      


# 파이썬 관련 패키지 설치 할 때 꼭 필요.

sudo apt-get -y install python-dev


# 파이썬 mysql 관련 패키지 설치시 필요

sudo apt-get install -y  libmysqlclient-dev


# 파이선 이미지 관련 라이브러리에서 필요, Pillow 같은 라이브러리 설치시 필요함

sudo apt-get install -y libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk

# 소스 관리툴 git 를 위해 사용함 
sudo apt-get install git 





3. nginx 설치
 nginx 를 사용하는 경우, 소스다운로드 받을 디렉토리가 /usr/share/nginx  안인 경우가 많다. nginx 를 설치하면 해당 경로를 자동으로 만들어주기 때문에 
nginx 를 먼저 설치하는 편이다. 

sudo apt-get -y  install nginx






4. 소스 다운로드
일반적으로 소스배포는 git를 이용하는 편이다. 그리고 git를 사용할 때는 배포용 전용 아이디를 만들어서 read 만 되게 관리한다.

소스 경로는   /usr/share/nginx/[프로젝트명] 식으로 하는 편이다.
cd /usr/share/nginx/[프로젝트명]
로 git로 소스를 다운받을 위치로 이동한다. 


github 의 경우
sudo git clone https://아이디@github.com/github프로젝트경로  .
맨 끝의 .(점) 의 경우 현재 디렉토리에 넣겠다는 의미이다. 맨 끝의 점이 없는 경우 새롭게 디렉토리가 생성된다. 


이를테면 
sudo git clone htttps://yiunsr@github.com/yiunsr/re2view.git .   
이런식으로 git의 경로는 https://github.com/yiunsr/re2view.git 이런식이다. 
 
bitbucket 의 경우
sudo git clone https://아이디@bitbucket.org/bitbucket프로젝트경로      .
으로 github 와 유사하다.  역시 맨 끝에 현재 위치에 다운받으라는 의미로  .(점)이 들어 있다. 

일반적으로 파이썬으로 만들어 프로그램 또는 서버는 virtualenv 로 가상환경을 설정해서 만들어진다. 나의 경우 실제 서버에서도 이런 방식으로 하는 편이다. 테스트 환경의 경우, 특히나 한 서버에 여러 서비스를 올리는 경우가 많았기 때문에 서로의 서비스가 영향을 받지 않도록 하려고 virtualenv 를 사용하는 편이다. 따라서 이 경우 pip freeze 한 결과파일 파일을 두고 다시 세팅하는 편이다. 이런 환경이 없다면 이번 기회에 이런 방식으로 사용하기를 추천한다. 


5. python 라이브러리 및 virtualenv 설정
요즘에는 파이썬이 2버전과 3버전 모두 탑재되는 경우가 많다. 그래서 설치가 되어 있다고 가정하고 진행한다.
(아주 최신 버전을 고려할 경우 따로 컴파일 후 설치할 필요가 있다. )

아래 설명은 python2.7 기준이다. python3 버전은 차후에 여기 아래에 추가 하겠다. 

python 패키지 관리자 pip 를 설치하고 pip 를 통해 virtualenv 를 설치한다.

apt-get install -y python-pip

pip install virtualenv

 


나 같은 경우 따로 설치한 프로그램은 /opt/ 에 넣는 편이다. 그래서 python virtual 환경 경로도 /opt/env/  아래 두는 편이다. 

우선 해당 디렉토리 까지 만든다. 그리고 가상환경을 만든다. 

cd /opt/

mkdir py_envs

cd py_envs

virtualenv --no-site-packages --distribute vtest

 


이 다음 중요한 것이 있다.
꼭 가상환경을 설정하기 전에
sudo -s   
를 해서 꼭 root 접속 필요하다.
sudo 를 이용해서  pip로 파이썬 패키지를 설치하면,  path 가 맞지 않아서 뭔가 제대로 동작하지 않았다. 

sudo -s            ### 꼭 root 접속 필요(sudo 를 이용한 pip 를 화면 path 가 맞지 않는다. 

source /opt/py_envs/vtest/bin/activate 를 이용해서 해당 상태를 활성화 시킨다.


그리고 자신에게 필요한 패키지를 설치한다. 경우에 따라서는 아래 git 를 통해 소스를 다운받은 후에 

pip install -r requirements.txt

식으로 pip freeze  를 한 결과를 저장해둔 파일을 이용해 한 방에 설치할 수도 있다.



6. uwsgi 설치 및 설정 

uwsgi 는 Djanog 와 wsgi 방식으로 연동시켜준다.  Nginx 없이  uwsgi + Django 만으로도 실서비스가 가능하다. 그리고 uwsgi 도 어떠한 이유로 죽을 수 있고 경우에 따라서는 컴퓨터가 어떠한 이유로 죽어서 재부팅 할 수도 있다. 이를 위해 죽을 때 다시 살릴 수 있고 부팅할 때 자동으로 동작할 수 있도록 해야 하는데 이 때 사용하는게 요즘은 systemd 이다. 이 연동을 하기 위해 uwsgi를 Emperor Mode로 사용해야 한다. 


우선 uwsgi 를 설치한다.

# (virtualenv 를 이용한 상태가 아니어야 한다. ) 

sudo pip install uwsgi



uwsgi 환경 설정을 할 수 있는 파일 생성한다. (차후 다른 프로젝트도 같이 돌아가는 경우, 이 경로에 다른 이름으로 파일을 생성한다. _

sudo mkdir -p /etc/uwsgi/sites

cd /etc/uwsgi/sites/


## 환경설정 파일 생성

sudo vim [프로젝트명].ini    



==== [프로젝트명].ini ====
[uwsgi]

#한 서버에 여러 프로젝트 파일을 올린 경우, 이 port 가 절대 겹치면 안된다. 
# 아래 있는 socket의 .sock 파일 대신 Nginx와 연결할 때 사용할 수도 있다.
# 실제로 이 port 를 통해 외부에 접속할 수 있다. 
http-socket = :9001  
master=True
pidfile=/tmp/[프로젝트명].pid  

chmod-socket=666
socket=/tmp/uwsgi_[프로젝트명].sock  #Nginx 와 연동할 때 연결되는 부분이다. 
processes = 2  ## 생성된 process 개수, 일반적으로 process 개수와 맞게 생성한다.
vacuum=True
#max-requests=5000

### 해당 경로에 Django의 wsgi.py 경로가 있어야 한다. 
wsgi-file = /usr/share/nginx/[프로젝트명]/djanog내_경로/wsgi.py  

## request 할 때 body를 제외한 사이즈,  기본사이즈는 4k 인데, 16k 로 늘렸다. 
## datatable.js 를 매우 애용하는데, 이 때, 여려 옵션들을 이용하면 Get Method 인데도 엄청 많은 parameter 가 전달되어 
## 크게 늘렸다. 
buffer-size=65535  


virtualenv = /opt/py_envs/virtual_env를생성한 경로    ## 여기서는 /opt/py_envs/vtest
touch-reload = /usr/share/nginx/[프로젝트명]/djanog내_경로/wsgi.py
logto = /var/log/uwsgi/[프로젝트명].log
chdir=/usr/share/nginx/[프로젝트명]
logfile-chown=www-data
logfile-chmod = 644

## 실제 이 경로는 Django Project에서 어떤 곳에 static 이 위치에 있는지에 달려있다.
static-map = /static=/usr/share/nginx/[프로젝트명]/static  

========



위에서 tocuh-reload 는 서비스를 다시 시작하지 않아도 해당 파일의 수정일자에 변경이 있으면 자동으로 서비스가 동작하도록 하는 부분이다.  만일 다른 부분이 다 수정되어 있는데도, 해당 파일의 수정일자가 변경되지 않는다면 메모리에 올라간 시스템이 적용되지 않고 계속 적용된다. 
그래서 내경우는 wsgi.py 파일의 주석을 변경하고 git 에 commit 해 두고 나중에 git pull 할 때 자동으로 수정하도록 한다. 경우에 따라서는 version.txt 파일을 만들어 운영하는 것도 좋은 방법이라고 생각한다. 
딱히 해당 파일의 변경사항이 없을 때는
sudo touch  /usr/share/nginx/[프로젝트명]/djanog내_경로/wsgi.py
touch 명령어도 최종수정일자를 갱실해 주면 된다. 


다음은 위 ini 파일에서 로그 파일 까지의 디렉토리를 생성해 줘야 한다. 해당 파일이 없으면 에러가 발생하기 때문에 실행전에 꼭 log 디렉토리를 만들어 두어야한다. 

uwsgi 전용 log 파일 경로 생성

sudo mkdir -p /var/log/uwsgi

sudo touch  /var/log/uwsgi/[프로젝트명].log #touch 는 파일이 없는 경우 빈 파일을 생성해 주기도 한다. 

sudo chown  -R  www-data.www-data /var/log/uwsgi/


여기 까지 작업을 했다면 uwsgi 를 돌려볼 수 있다.
시작 
uwsgi  --uid www-data  --gid www-data  --ini /etc/uwsgi/sites/[프로젝트명].ini &

정지
uwsgi --stop /tmp/[프로젝트명].pid

으로 돌릴 수 있다. 에러가 발생하면 로그파일 생성한 곳( /var/log/uwsgi/[프로젝트명].log )으로 가서 로그 확인이 필요하다. 
꼭 시작 명령어로 돌렸으면 정지 명령어로 종료해야 한다.
( kill 명령어로 죽였다면 다시 돌릴려면 /tmp/[프로젝트명].pid 파일을 삭제해야 돌아간다. 해당 pid 파일이 있는 상태로 다시 시작을 시키면 pid 파일이 있어서 이미 프로세스가 돌아가고 있다고 생각해서 시작하지 않는다. ) 

http-socket 를 설정하고 방화벽(리눅스내 ufw 방화벽, 그리고 서비스에서 제공하는 방화벽 모두 open 되어야 한다.) 이 open 되어 있다면 외부에서 접속할 수 있다. 이 접속까지 되어야 다음 설정을 진행할 수 있다. 


7.   uwsgi 의  systemd 설정
uwsgi 도 프로그램이기 때문에 죽을 수 있고 재부팅 마다 시작 설정(uwsgi  --uid www-data  --gid www-data  --ini /etc/uwsgi/sites/[프로젝트명].ini &
 ) 을 하는 것을 정말 귀찮기 때문에 systemd 를 설정해 준다.

sudo vim /etc/systemd/system/uwsgi.service


==== uwsgi.service ====

[Unit]
Description=uWSGI Emperor service
After=syslog.target

[Service]
ExecStart=/usr/local/bin/uwsgi  --emperor /etc/uwsgi/sites

Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all

[Install]

WantedBy=multi-user.target 

========


ExecStart=/usr/local/bin/uwsgi  --emperor /etc/uwsgi/sites
에서 uwsgi 가 경로가 다르면 오류가 발생할 수 있다. 만일 그렇다면 which uwsgi 로 경로를 확인 할 수 있다.

설정 파일을 만들었으니 이제 systemd 에 부팅시에도 동작할 수 있도록 하자
sudo systemctl enable uwsgi # 부팅시 자동시작
(만일 부팅시 자동 시작을 막고 싶으면 sudo systemctl disable uwsgi  

이제
sudo service uwsgi 형태로 서비스를 관리 할 수 있다. 

서비스 시작
sudo service uwsgi start   # 이 명령어가 안된다면    sudo systemctl start uwsgi     로 사용할 것

서비스 중지
sudo service uwsgi stop   # 이 명령어가 안된다면    sudo systemctl stop uwsgi     로 사용할 것

서비스 재시작(stop + start)
sudo service uwsgi restart   # 이 명령어가 안된다면    sudo systemctl restart uwsgi     로 사용할 것

서비스 재로드(환경설정 파일만 재로딩)
sudo service uwsgi reload   # 이 명령어가 안된다면    sudo systemctl reload uwsgi     로 사용할 것


만일 uwsgi  --uid www-data  --gid www-data  --ini /etc/uwsgi/sites/[프로젝트명].ini &
로 프로세스가 돌아가고 있다면 sudo service uwsgi start   가 안될 수도 있으니 꼭 종료하고 동작시키자. 


8. nginx 설정

uwsgi 만으로도 서비스는 동작시킬 수 있지만, nginx 을 통해 보안기능을 좀더 확보하고, static 리소스(css, js, 이미지 파일들)를 접근하는데 더 안정적으로 동작하고,  여러 다양한 기능(gzip 기능 같은 것)을 이용할 수 있기 때문에 nginx 를 uwsgi 앞에 둔다. 
이렇게 nginx 를 사용하는 경우, reverse proxy 를 사용한다고 합니다. 

우선 로그 포멧 및 gzip 사용을 위해 아래 주소에 로그 포맷을 추가 한다. 

sudo vim /etc/nginx/nginx.conf

 

==== nginx.conf ====

http{


    ## gzip 관련 주석 해제

    gzip on;

  gzip_disable "msie6";

   

  gzip_vary on;

  gzip_proxied any;

  gzip_comp_level 6;

  gzip_buffers 16 8k;

  gzip_http_version 1.1;

  gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;


   …….


     log_format  post_log '$remote_addr - $remote_user [$time_local]    "$request" '

                      '$status $body_bytes_sent "$http_referer" '

                       '"$http_user_agent" $request_time "$request_body"'



     …


}


========


log_format   의 경우 필요없는 경우 추가 할 필요 없다. 해당 코드는 웹에서 Post method 로 보낼 때에도 log 파일이 보일 수 있도록 하는 설정에 대한 포멧이다. 여기서 설정을 했다고 해서 post_log 가 보이는 것은 아니고 그냥 포멧을 지정하는 것이기 때문에 우선 추가한다. 



만일 SSL 인증서를 적용하는 경우라면 해당 인증서에 나와있는 가이드와 아래 코드와 적절히 조화가 필요하다. 이 부분은 case 가 너무 많은지라 가이드 하기 어렵다.... 


이제 /etc/nginx/sites-available/

내에 실제 설정 파일 추가한다. 따로 설정파일이 없는 경우 /etc/nginx/sites-available/default   파일의 설정대로 동작한다. 


설정파일이름은 프로젝트명으로 하기보다는 domain 으로 많이 이용하는 편이다. 그런데 거기에 따른 영향이 딱히 없기 때문에 그냥 구별할 수 있을 정도로 정하면 된다.

vim /etc/nginx/sites-available/[프로젝트명 또는 domain]


==== [프로젝트명 또는 domain ]
server {
    listen 80;
    server_name [domain];
    client_max_body_size 100M; ## 크기가 작을 경우 업로드 할 때 제한이 생길 수 있다. 

    root /usr/share/nginx/[프로젝트명]/;
    access_log /var/log/nginx/[프로젝트명]_access.log;
    access_log /var/log/nginx/[프로젝트명]_post.log   post_log;

    error_log /var/log/nginx/[프로젝트명]_error.log;

    location /static/ {
        alias /usr/share/nginx/[프로젝트명]/static/;   ## django 내 static 경로를 맞춰야 한다. 
    }

    location / {
        uwsgi_pass unix:/tmp/uwsgi_[프로젝트명].sock;
        include uwsgi_params;
    }

    
}

 


 access_log /var/log/nginx/[프로젝트명]_post.log   post_log;

이 부분이 들어갈 경우 Post Method 가 들어가 있는 부분에 로그가 출력되기 때문에 로그파일이 꽤 크게 생성된다.

내 경우 테스트 서버의 경우 디버깅을 위해 넣는다. (사내에서만 돌아가는 서비스 인 경우에도 넣는 편이다. ) 
실서버의 경우 굳이 해당 부분을 넣을 필요가 없을 것 같다. 


listen 80;
이 부분은 열리는 포트이다. 일반적으로 80포트이나, SSL 이 이용되는 경우 443 포트를 이용할 수 있다. 

server_name 은 실제 사용하는 domain, 없는 경우 public ip 주소를 사용할 수 있다. server_name 을 여러가 나열하거나 domain 과 ip 를 같이 사용할 수 도 있다.  그럴 경우   
server_name  www.labstoo.com   imglst.labstoo.com    m.labstoo.comm;
이런 식으로 옆으로 나열 하면 된다.

uwsgi_pass 부분은 uwsgi 에서 만든 sock 파일과 매칭되어야 정상적으로 동작한다. 

이제 nginx 를 돌려보자. nginx 는 설치시 자동으로 service 로 등록되기 때문에 serivce 명령어를 사용할 수 있다. 

시작
 sudo service nginx start

종료
 sudo service nginx stop

웹브라우저로 접속시 503 에러가 나면 nginx 에서 uwsgi 연결이 잘못된 것이다.



8. (옵션) 로그 관리 설정

서버를 운영하다보면 많은 로그가 생성된다. 이 경우 로그파일이 크면 서비스가 동작하지 않을 수도 있다. (로그파일을 만들지 못해 서비스가 동작하지 않는 경우가 있다. hard 가 작은 경우 이런 case 를 몇 번 겪어 봤다.) 

그래서 로그를 압축하고 너무 오래된 로그는 지우도록 설정한다. 

uwsgi 의 경우 이미 되어 있는 설정이 없기 때문에 설정이 필요하다. 

로그 관리의 경우 /etc/logrotate.d  내 설정이 되어 있다.

nginx 의 경우 이미 로그 설정이 되어 있다. 그러나 기본적인 설정이기 때문에 설정변경이 필요하다. 

sudo vim /etc/logrotate.d/nginx


==== nginx ====

/var/log/nginx/*.log {

        daily

        missingok

        rotate 30

        compress

        delaycompress

        notifempty

        create 0640 www-data adm

        sharedscripts

        prerotate

                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \

                        run-parts /etc/logrotate.d/httpd-prerotate; \

                fi \

        endscript

        postrotate

                invoke-rc.d nginx rotate >/dev/null 2>&1

        endscript

        dateext

}

 ========


dialy 는 파일이 나눠어 지는 시간단위 이다.   daily / weekly/ monthly  같이 사용할 수 있다. 

rotate 의 경우 로그파일을 관리할 개수이다. dialy 로 관리되기 때문에 30일 까지 관리된다.

dateext 는 파일이 따로 분리 될 때  날짜를 확장자로 사용하겠다는 의미이다. 



다음은 uwsgi 용 로그 설정이 필요하다. uwsgi 의 경우 생성되는 파일이 없어서 생성해야 한다.

 sudo vim /etc/logrotate.d/uwsgi


==== uwsgi ====
"/var/log/uwsgi/*.log" "/var/log/uwsgi/*/*.log" {
  copytruncate
  daily
  rotate 30
  compress
  delaycompress
  missingok
  notifempty
  dateext
}

========


로 설정하면 된다.


logrotate 의 경우 해당 동작이 crontab 에 의해 동작한다.  

(/etc/cron.daily/logrotate 파일이 존재한다. ) 





모든 설정이 끝났다. 혹시 추가 사항이 있는 경우 계속 최종수정일을 고쳐가면서 수정하도록 하겠다. 
혹시 잘못된 설정이나 더 좋은 방법 있으면 댓글을 남겨두기 바란다. 


최종수정일  2018년 03월 02일





 Django 를 많이 사용하면서 많은 서버를 세팅했는데, 한 번도 내 블로그에 정리해 본적이 없는 것 같다. 인터넷에서 많은 정보를 얻어왔는데, 이번에는 나도 다른 사람들에게 도움이 될 수 있도록 이글을 남긴다. 내 경우 사수없이 혼자서 공부해서 세팅한 경우가 많기 때문에 많은 내용들이 공식적인 내용이 아니라 좀 많이 야매이다. 이 점을 좀 고려해서 아래글을 읽기 바란다. 



 일반적으로 개발할 때는 Django 을 테스트 모드로 설정해 자체적인 서버로 동작한다. 지금은 테스트 모드로 동작하는 서버도 멀티프로세스로 동작하는 것 같은데 초장기에는 싱글 프로세스라서 매우 느렸다. (그런데 이게 싱글프로세스 였는지, Eclipse + Pydev 가 멀티 프로세스를 지원하지 않은 것인지 잘 기억이 나지 않는다. ) 그리고 뭣 모르고 그 상태로 상용서비스에 올리기도 했다. 물론 그 서버는 내부 관리 사이트여서 죽어도 크게 문제가 되지 않긴 했다. 


 그리고 나중에 서버에서는 꽤 복잡하게 동작한다는 것을 이해했다. 일반적으로 서비스, daemon 이런 것이 돌아 갈 때는 죽지 않게 하기 위해 실제 코드가 돌아가는 부분은 따로 process 를 생성해서 동작한다. 그래서 그 process 는 죽더라도 메인 process 가 죽지 않아서 계속 돌아갈 수 있도록 한다. 그리고 그 process 도 CPU core 나 하이퍼쓰레드 지원등을 고려해서 여러개 생성한다. 또 main Process 자체가 죽을 수 있으니 서비스로 등록해서 죽지 않도록 하기도 한다. 


우선 리눅스를 다룬적 없다는 가정하여 몇가지 기본 명령어에 대해 설명하겠다. 


1. 퍼미션 유저 그룹

서버의 경우 퍼미션과 유저, 그룹에 대해 민감한 편이다. 서비스가 설치된 폴더는 일반적으로 최소의 퍼미션을 유지하고 유저, 그룹도 최대한 권한이 없어야 한다. 해당 서비스가 돌아갈 때도 따로 유저, 그룹을 설정한다. 일반적으로 Ubuntu 에서는 www-data 를 유저로 www-data 를 그룹으로 설정한다. 


2. ps 명령어

프로세스 검색은 ps 를 통해 확인 한다. 나의 경우 습관적으로 옵션을 aux 까지 붙여 ps -aux 를 하는 편이다. a 옵션은 다른 사용자 프로세스 까지 보여주는 것인데 프로세스를 다른 사용자로 돌리는 경우가 많으므로 필수이다. u는 프로세스 별 유저와 시간을 보여준다. x  옵션은 현재 로그인 한 세션에서 생성된 것 뿐만 아니라 모든 프로세스를 보여준다. 


모든 OS의 콘솔에서 파이프를 이용해 어떤 명령어의 결과를 다른 명령어의 argument 로 이용할 수 있다. 이러한 방식으로 입력을 받는 대표적인 프로그램이 grep 라는 프로그램이다. 

ps aux | grep nginx 

라고 하면 ps aux 의 결과를 입력으로 사용해서 grep 는 ps aux 의 결과 중 nginx 라는 글자가 발견된 라인만 출력하다. 다만 여기서 grep 라는 명령어가 동작하면서 이 것도 다시 ps aux 에 나오게 된다. 그래서 nginx 라는 프로세스가 안돌고 있어도

hanmil 11575 0.0 0.0 15508 1080 pts/1 S+ 23:15 0:00 grep --color=auto nginx

이런식으로 grep 프로세스가 nginx 라는 argument 가 들어간 부분도 보여질 수 있다.


어쩌든 ps aux | grep nginx     하면 nginx 라는 프로세스가 있는지 확인할 수 있다.

이 동작은 프로세스가 동작하는지 확인 뿐만아니라 pid 를 확인 해서 프로세스를 강제로 종료 할 때도 많이 사용된다.


=============

hanmil@ubuntu:~$ ps aux |grep nginx

root      1164  0.0  0.0 125112  1448 ?        Ss   21:56   0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;

www-data  1165  0.0  0.1 125436  3140 ?        S    21:56   0:00 nginx: worker process

hanmil   11616  0.0  0.0  15508  1092 pts/1    S+   23:23   0:00 grep --color=auto nginx

=============


붉은 색으로 표시한 부분이 pid(process id) 이다. 이 id 를 가지고 프로세스를 강제로 죽일 수 있다.

이를 테면  kill -9 1165     이렇게 할 수 있다.  그런데 이 상황에서는 로그인 한 유저는 hanmil 이고 프로세스 1165는  www-data 라는 유저의 프로세스이기 때문에 해당 프로세스를 죽일 수 없다. 이 때는 sudo 를 이용해서 잠시 root 권한을 가져야 한다. 

그래서  sudo kill -9 1165   이렇게 해야한다.



3. pid 파일

uwsgi 를 설정할 때, pid 을 설정하게 된다. pid 는 프로세스 정보가 담긴 파일이다. 그래서 가끔 pid 파일을 생성하는 데몬을 돌리다가 강제로 죽이면 pid 

파일은 그대로 남아 있는 경우가 있다. 정상적인 종료일 경우 프로그램이 종료되면서 pid 파일을 스스로 삭제해야 하나 강제로 죽이면 이러지 못한다. 그런데 이 상태로 다시 uwsgi 를 실행하면 pid 파일이 남아 있어 프로그램이 중복 실행하는 줄 알고 실행이 안되는 경우가 있다. 이 때는 그냥 pid 파일을 삭제하고 uwsgi 를 실행하면 된다. 



4. apt-get

리눅스에는 구글플레이나 앱스토어 처럼 여러 프로그램을 모아둔 리눅스 프로그램 서버가 있다. 보통 repository 라고 부른다. 이 리포지토리에 저장된 프로그램을 관리하는 명령어가 ubuntu 에서는 apt-get 이고 centos 에서는 yum 이다. 

리포지토리는 기본 저장소가 있고 이 저장소의 여러 mirror 들이 있어 보통 같은 국가에 있는 저장소를 이용한다. 리포지토리 URL들이 저장되는 곳은 /etc/apt/sources.list 이다. 그리고 기본저장소는 안전성을 위해 리눅스 배포판이 처음 만들어 질 때의 버전의 프로그램이 있기 마련이다. 그래서 최신 버전의 프로그램을 받기 위해 기본 저장소가 아닌 저장소를 추가 하기도 한다. 이런 저장소를 PPA(Personal Package Archive) 저장소라고 한다. 

 CentOS 의 경우 이런 PPA 저장소 중에 자주 사용하는 것이 epel, remi 이고 Ubuntu 도 있는데 아직 사용해 본적은  없어서 잘 모르겠다........

 경우에 따라서는 바이너리 프로그램을 바로 설치하기도 하는데 윈도우즈에서 파일 확장자가 .exe 이 듯이 CentOS 계열은 확장자가 .rpm 이고 .deb 파일이다. 


어째든 Ubuntu 에서는 여러 프로그램(nginx, mysql 같은 것들)  apt-get 으로 인터넷으로 바이너리를 다운받아 설치할 수 있다. 

설치를 위해서는  sudo apt-get install 패키지명 ,  삭제를 위해서는 sudo apt-get uninstall 패키지명  이다. 




5. netstat 

프로그램이 잘 돌아가면서 port 를 열고 기다리는지 확인 하는 용도로 사용된다. 

나의 경우 netstat -apt  같이 사용한다. 

a 옵션은 all 을 의미하고 포트를 사용하는 process_id,  t 는 tcp 소켓을 의미한다.


이렇게 할 경우 대기하고 있는 포트들이 보인다. 간혹  0.0.0.0:80  이나 ::80   또는 127.0.0.1:80  이런식으로 표시된다. 127.0.0.1 인 경우 외부에 들어나지 않고 내부에서만 접속 가능한 port 라는 의미이다. 따라서 외부에서 접속해야 하는 경우 절대 127.0.0.1 로 보이면 안된다. 


6. telnet 

예전에 PC 통신 이라는게 있었는데, 이런 서비스들은 telnet 기반의 서비스이다. 이런 telnet 은 윈 포트가 잘 접속되는지 확인 하는 용도로 많이 사용한다.  서버가 리눅스인 경우가 많지만 개발자의 PC는 윈도우즈인 경우가 많다보니 telnet 를 윈도우즈 리눅스에서 같이 사용될 수 있는 telnet 이 사용된다. 윈도우즈의 경우 제어판에 들어가 윈도우즈 기능을 추가해야 할 수도 있다. (이 부분은 인터넷 검색을 하도록...)

telnet 도메인이나ip  포트번호

보통

========

C:\programs\pros\conemu>telnet 1.1.1.1 80

연결 대상 1.1.1.1...호스트에 연결할 수 없습니다. 포트 80: 연결하지 못했습니다.


C:\programs\pros\conemu>

==========

이런 식으로 이용된다. 이 경우 1.1.1.1 이라는 서버의 80 포트로 연결이 안된다는 의미이다. 만일 해당 서버에서 netstat -apt 했을 때 127.0.0.1 이 아니고 그냥 80포트가 열려 있다고 한다면 해당 리눅스 서버에서 방화벽이 오픈되지 않았거나 하나 서버를 사용하는 호스팅에서 제공하는 방화벽이 열리지 않았을 수도 있다. 이런식으로 연결 상태를 확인 하기 위해 telnet 을 많이 이용한다. 





다음에는 실질적인 실질적으로 서버 세팅을 하도록 하겠다.