월풍도원 블로그의 컨텐츠를 정리한 dorajistyle.net

블로그에 글을 하나둘씩 적다 보니 제법 쌓여서 1,000개가 넘었다.
구글 블로그는 글을 쓰고 올리기는 좋지만 썼던 글을 찾아보기는 영 불편하다.
RSS를 동적으로 받아와서 분류해 보았지만, 동적으로 받아 오니 글 개수가 늘어날수록 성능이 떨어진다.
그래서 작년 가을에 static블로그를 하나 만들어야겠다고 마음을 먹고 가볍게 시작했다.
Jekyll, Octopress, Pelican, Middleman, Metalsmith등 다양한 Static site generate를 사용해 봤지만 아쉬움이 남았는데,
다양한 플러그인을 제공하는 Docpad를 알게 되어 이를 가지고 static 사이트 제작을 시작하였다.
며칠이면 뚝딱 만들 줄 알았는데 이게 1년 넘게 걸리는 대장정이 될 줄은 몰랐다.
Pure로 테마와 레이아웃을 간단하게 제작하고, 본격적으로 글을 옮기는 시도에 들어가면서 시간이 오래 걸렸다.
제일 큰 문제는 파일 개수가 너무 많으면 docpad에서 제대로 처리를 못 하는 것이었다.
generate를 한 번 실행하면 한 시간이고 두 시간이고 혼자서 자원을 잡아먹으며 시간을 보내고는,
‘오류가 발생한 것 같은데요?’
라는 메시지를 딸랑 던져줄 때 허무함이란 이루 말할 수 없었다.
버그를 한둘씩 잡다 보니 사계절이 지났다.
‘static 블로그는 무슨 static블로그냐. 집어 치우자.’
라는 생각과
‘그래도 지금까지 들인 공이 있는데 끝을 보자.’
생각이 교차하길 여러 번.
올해를 넘기지 않고 blogger-docpad를 완성했다.
이제 이 도구를 어디 노는 서버에 넣어 두고 cron을 돌려 두면, 구글 블로거에 글을 쓸 때마다 자동으로 static 블로그에 업데이트되는 거다.
글을 올리면 수작업으로 한 땀 한 땀 업데이트하는 재미도 있겠지만,
기계가 해도 되는 일을 수작업하는 건 무척 귀찮은 일이다.

꼭 하지 않아도 될 일을 하면서 사는 건 슬픈 일이다.
사람은 좀 더 게으르고 즐겁게 살 권리가 있다.

dorajistyle.net



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

4G램 이하에서 Arch linux를 데스크탑으로 쓰기 위한 최적화.

램이 4G라면 적은 건 아니다. 하지만 무거운 프로그램을 돌리려면 부족한 게 사실이다. 이를 해결하려고 Desktop Environment을 바꿔 보았지만 별 효과를 보지 못했다. 그래서 몇 가지 더 손을 본 결과 쓸만한 데스크탑 환경을 구축했다.

가장 큰 효과를 본 것은 스왑 메모리의 설정이었다. SSD에 자주 쓰고 지우면 수명이 단축된다고 하지만, 내 수명이 단축되지 않으려면 스왑을 써야했다. 스왑영역을 잡아주었더니, 버츄어 박스와 IDE 크롬과 파이어폭스를 띄워도 시스템이 멈추지 않는다.

스왑 할당하기

우선 아래 명령어로 할당된 스왑을 확인한다.
sudo swapon -s
free -m

공간이 충분히 남아있는지도 확인한다.
df -h

스왑 파일을 만든다.
sudo fallocate -l 4G /swapfile

root 유저만 읽고 쓰도록 스왑 파일의 권한을 설정한다.
sudo chmod 600 /swapfile

스왑 파일이 잘 만들어 졌는지 확인한다.
ls -lh /swapfile

스왑 영역을 할당한다.
sudo mkswap /swapfile

스왑 영역을 활성화한다.
sudo swapon /swapfile

아래 명령어로 할당된 스왑을 확인한다.
sudo swapon -s
free -m

/etc/fstab 파일에 스왑 설정을 추가한다.
/swapfile none swap sw 0 0

/etc/sysctl.conf 파일에 다음을 추가한다.
vm.swappiness=10
vm.vfs_cache_pressure = 50

스왑 영역을 지울 땐 아래 명령어를 쓰면 된다.
swapoff -a
rm -f /swapfile

gnome-pty-helper 비활성화

사용자가 얼마나 많은 터미널을 열었나 기록하는 헬퍼로 데스크톱 환경에서는 필요가 없다.

chmod 644 /usr/lib/vte/gnome-pty-helper
chmod 644 /usr/lib64/vte/gnome-pty-helper
chmod 644 /lib64/vte/gnome-pty-helper
chmod 644 /lib/vte/gnome-pty-helper

Core dump 비활성화

코어 덤프가 디버깅엔 유용하지만 평소에는 성능에 저하를 가져오므로 비활성화 한다.
/etc/sysctl.conf 파일에 다음을 추가한다.
fs.suid_dumpable = 0

SSD trim 기능 켜기

sudo pacman -S util-linux
sudo systemctl enable fstrim.timer

윈도우 메니저의 변경이 도움이 될 수도 있다.
가벼운 윈도우 메니져가 많다. FVWM과 ICEWM이 가벼운 편이었지만, 보기가 너무 안좋아서 지워버렸다. OpenBox는 좋은 모습을 보여주지만 XFCE의 기본 WM인 XFWM(14M)보다 두배가 넘는 메모리(31M)를 사용한다. 그래도 여전히 가벼운 편이니 취향에 따라 OpenBox로 윈도우메니져를 바꿔 보는 것도 괜찮겠다.

xfce 윈도우 메니저 변경하기

설정 파일을 가져온다.

cp /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml

~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml 파일을 열어 xfwm4를 openbox로 변경한다.

<value type="string" value="xfwm4"/>to
<value type="string" value="window_manager_executable"/>

오픈박스용 설정 설치

pacman -S obconf

단축키가 제대로 동작하지 않으면 vi .config/openbox/rc.xml 에서 사용하지 않는 단축키를 제거한다.

지금 사용하는 윈도우 메니저 보기

pacman -S wmctrl
wmctrl -m

가볍고 쓸만한 앱을 찾다가 보조 터미널로 좋은 tilda와 자원 점유율을 보여주는 htop을 설치했다.

pacman -S tilda
pacman -S htop


혹시 이 환경에서도 시스템이 불안정한 일이 자주 발생한다면 쓰는 자주 프로그램을 가벼운 걸로 바꾸어 보는 것도 괜찮을 것 같다. 예를 들면 이메일 클라이언트를 썬더버드에서 Trojita나 Geary등으로 바꾸는 것이다. 하지만 설정을 다시 하기는 귀찮으니 우선은 이대로 써야겠다.


문제 해결

키보드 단축키가 작동하지 않을 때

로그아웃 하고 tty1(ctrl+alt+F1)에서 로그인 하여 rm -rf ~/.cache/sessions/* 로 세션 캐쉬를 삭제한다.

Failed to fork (Resource temporarily unavailable) 오류가 날 때

/etc/sysctl.conf 파일에 다음을 추가한다.
fs.file-max = 204708

QT5에서 한글 입력이 안될 때

yaourt -S uim-qt5 --force

SHELL의 변경 (zsh)

pacman -S zsh
zsh /usr/share/zsh/functions/Newuser/zsh-newuser-install -f
chsh -s $(which zsh)
echo $SHELL

재부팅 하지 않고 sysctl 적용

sudo sysctl -p /etc/sysctl.d/99-sysctl.conf

그 밖에 읽어볼 만한 자료.

SSD 최적화

베터리를 오래가게 돕는 도구

실행중인 프로세스가 어떻게 자원을 사용할 지 제어하는 데몬



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

Arch Linux에 LXQt desktop environment 설치하기

구글 크롬만 띄우면 컴퓨터가 숨을 할딱인다. 아주 멋진 새 컴퓨터를 사든지, 크롬 정도는 식후 간식거리로 여길 만큼 튼튼한 환경을 만들든지 해야겠다. 이 ‘구글 크롬 시전시 일정 확률로 멍해짐’은 귀차니즘에 밀려서 오랫동안 억지로 외면해온 현상인데 이제 좀 해결할 때가 되었다. Xfce도 가볍고 안정적인 데스크톱 환경으로 소문났지만, 크롬을 안정적으로 돌리려면 좀 더 가벼운 환경이 필요하다.

어떤 데스크톱 환경이 좋을까?
아치 리눅스 위키(https://wiki.archlinux.org/index.php/Desktop_environment)를 보니 수 많은 데스크톱 환경이 나를 반긴다.
가벼운 환경이 필요하니 KDE, 그놈, 시나몬, 유니티 등은 우선 제외.
가볍고 보기도 좋은 데스크톱 환경을 찾아보자.
우선 제일 눈에 띄는 환경은 엘레멘트리OS의 판테온(https://wiki.archlinux.org/index.php/Pantheon)이었는데, 최신 그놈이랑 무슨 문제가 있는지 싸웠는지 창의 이동이 안 되고 닫히지도 않으며 이래저래 제대로 동작하지 않는다.
이름도 거창한 Enlightenment는 가볍다고 하지만 사용성이 떨어진다.
LXDE는 윈도우 3.1모양새라 싫고 결국 LXQt에 관심을 두게 되었다.

LXQt(http://lxqt.org/)는 ‘차세대 경량 데스크톱 환경’으로 가벼운데다가 멋지기까지 한 데스크톱 환경이라고 한다.
LXQt 설명은 ‘옛날건 빠른 대신 비주얼이 오징어고, 요즘 것들은 겉만 번지르르하다. 하지만 LXQt는 둘의 장점을 취해서 빠르고 보기에도 좋다!’라는 느낌을 주는데,
마치 ‘이소룡은 죽었다. 성룡은 늙었다. 이연걸은 약하다.’라는 옹박 캐치프레이즈를 보는듯하여 기대를 품고 LXQt 설치에 들어갔다.

yaourt -S lxqt-desktop-git qterminal-git obconf-qt-git lxqt-openssh-askpass-git
pacman -S openbox oxygen-icons qtcurve sddm

이 두 줄의 코드로 설치가 완료된다.

기호에 따라 아래 유틸리티를 설치해서 쓰자.

  • pcmanfm-qt-git: LXQt 파일 관리자 (yaourt)
  • lximage-qt-git: The LXQt 이미지 뷰어 (yaourt)
  • lxqt-openssh-askpass-git: OpenSSH Askpass 모듈 (yaourt)
  • openbox: 추천 윈도우 매니저 (pacman)
  • sddm: 추천 디스플레이 매니저 (pacman)
  • qterminal: Qt 터미널 (pacman)
  • juffed: Qt 텍스트 에디터 (yaourt)
  • screengrab: 스크린캡쳐 (yaourt)
  • qps: 작업 관리자 (yaourt)
  • trojita : 이메일 클라이언트 (pacman)

설치가 끝나면 로그아웃하고, LXQt 세션을 시작하면 된다.



Xfce 환경-'Arch Linux에 LXQt 설치하기'
Xfce 데스크톱 환경


LXQt 환경-'Arch Linux에 LXQt 설치하기'
LXQt 데스크톱 환경

LXQt
깔끔하고 보기 좋다.
테마도 손보고 바탕화면을 바꿨더니 쓰던 Xfce와 별반 다르지 않다.
그런데 크롬을 실행했더니 먹통이다.
Xfce 세션에서는 잘 실행된다.
문제가 뭔지 모르겠다.
아무래도 LXQt 말고 다른 해결방법을 찾아봐야겠다.



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

아마존 AWS Elastic Beanstalk에 Python Flask 배포환경 구축을 위한 설정

아마존 Elastic Beanstalk은 애플리케이션을 올리기만 하면 Elastic Beanstalk이 용량 프로비저닝, 로드 밸런싱, 자동 조정,
애플리케이션 상태 모니터링에 대한 배포 정보를 자동으로 처리한다.
개발자는 개발에만 신경 쓰면 인프라는 아마존에서 다 해주겠다는 말이다.
이 얼마나 반가운 소리인가?
그러나 막상 Elastic Beanstalk를 쓰려면 손수 설정해야 하는 부분이 많다.
이 글에서는 static 파일을 아마존 CDN인 CloudFront를 통해 제공한다는 가정하에 크게 세 부분으로 나누어 설명하겠다.
첫째는 아마존 콘솔 단에서 IAM,S3,CloudFront설정이고,
둘째는 Elastic Beanstalk .ebextensions 설정.
마지막은 Python boto를 이용한 배포 스크립트다.
게으른 개발자로서 좀 편해 보고자 아마존 AWS Elastic Beanstalk을 쓰면서 환경 설정 때문에 애를 많이 먹었다.
AWS Elastic Beanstalk을 고려 중인 또 다른 개발자가 이 글을 읽고 같은 삽질을 않으면 좋겠다.

AWS 콘솔 설정

IAM 설정

배포 권한을 가진 Group를 만든다.
예제에서 그룹명은 Dorajistyle-deploy로 하겠다.
User인 dorajistyle은 Dorajistyle-deploy 그룹에 소속되어, 배포시에 dorajistyle유저 정보로 배포하게 된다.
Dorajistyle-deploy그룹은 아래의 policy를 가진다.
{
  "Version": "2012-10-17",
  "Statement": [
     {
      "Effect": "Allow",
      "Action": [
        "elasticbeanstalk:*",
        "ec2:*",
        "elasticloadbalancing:*",
        "autoscaling:*",
        "cloudwatch:*",
        "s3:*",
        "sns:*",
        "cloudformation:*",
        "rds:*",
        "iam:AddRoleToInstanceProfile",
        "iam:CreateInstanceProfile",
        "iam:CreateRole",
        "iam:PassRole",
        "iam:ListInstanceProfiles"
      ],
      "Resource": "*"
    },
    {
      "Sid": "QueueAccess",
      "Action": [
        "sqs:ChangeMessageVisibility",
        "sqs:DeleteMessage",
        "sqs:ReceiveMessage"
      ],
      "Effect": "Allow",
      "Resource": "*"
    },
    {
      "Sid": "MetricsAccess",
      "Action": [
        "cloudwatch:PutMetricData"
      ],
      "Effect": "Allow",
      "Resource": "*"
    },
    {
      "Sid": "Stmt110100200000",
      "Effect": "Allow",
      "Action": [
        "s3:*"
      ],
      "Resource": [
        "arn:aws:s3:::dorajistyle/*",
        "arn:aws:s3:::dorajistyle",
        "arn:aws:s3:::dorajistyle-static/*",
        "arn:aws:s3:::dorajistyle-static",
        "arn:aws:s3:::dorajistyle-deploy/*",
        "arn:aws:s3:::dorajistyle-deploy",
        "arn:aws:s3:::elasticbeanstalk-ap-northeast-1-000000000000",
        "arn:aws:s3:::elasticbeanstalk-ap-northeast-1-000000000000/*"
      ]
    },
    {
      "Sid": "Stmt130000013000",
      "Effect": "Allow",
      "Action": [
        "rds:*"
      ],
      "Resource": [
        "arn:aws:rds:ap-northeast-1:000000000000:db:dorajistyle"
      ]
    },
{
      "Sid": "Stmt1399636332000",
      "Effect": "Allow",
      "Action": [
        "elasticbeanstalk:*"
      ],
      "Resource": ["*","arn:aws:elasticbeanstalk:ap-northeast-1:000000000000:application/dorajistyle",
"arn:aws:elasticbeanstalk:ap-northeast-1:000000000000:environment/dorajistyle/dorajistyle"
,"arn:aws:elasticbeanstalk:ap-northeast-1:000000000000:applicationversion/dorajistyle/*"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "cloudformation:DescribeStacks",
        "cloudformation:DescribeStackEvents",
        "cloudformation:DescribeStackResources",
        "cloudformation:GetTemplate",
        "cloudformation:List*"
      ],
      "Resource": "*"
    }


S3 설정

S3버켓은 총 3개가 필요하다.

dorajistyle-deploy
배포용 zip파일을 업로드할 버켓이다. 사용자 dorajistyle만 접근 가능하며, 버켓 설정은 기본 그대로 사용하면 된다.

CORS Configuration
<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>


dorajistyle-static
static 파일을 저장할 버켓이다. 누구나 읽을 수 있는 버켓이다.

Bucket policy
{
 "Version": "2008-10-17",
 "Id": "Policy1394587645145",
 "Statement": [
  {
   "Sid": "Stmt1394587643817",
   "Effect": "Allow",
   "Principal": {
    "AWS": "*"
   },
   "Action": "s3:GetObject",
   "Resource": "arn:aws:s3:::dorajistyle-static/*"
  }
 ]
}


CORS Configuration
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>http://*.dorajistyle.pe.kr</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>http://*.www.dorajistyle.pe.kr</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>http://dorajistyle.elasticbeanstalk.com</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedHeader>Authorization</AllowedHeader>
        <AllowedHeader>x-requested-with</AllowedHeader>
        <AllowedHeader>origin</AllowedHeader>
    </CORSRule>
</CORSConfiguration>


dorajistyle
이미지등의 유저 컨텐츠를 저장할 버켓이다.
예제에서는 모든 유저가 읽을 수 있도록 설정되었는데, 이는 사용 용도에 따라 변경이 가능하다.

Bucket Policy
{
 "Version": "2008-10-17",
 "Id": "Policy1394587559249",
 "Statement": [
  {
   "Sid": "Stmt1394587510887",
   "Effect": "Allow",
   "Principal": {
    "AWS": "*"
   },
   "Action": "s3:GetObject",
   "Resource": "arn:aws:s3:::dorajistyle/*"
  }
 ]
}


CORS Configuration
<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>


CloudFront 설정

dorajsityle-static S3에 CloudFront를 연결한다.
Origin Domain Name에 S3 버켓 주소를 적으면 된다.
만약 CloudFront에 연결이 잘 되었는데도 리소스를 찾지 못한다면 Invalidations에서 해당 리소스를 무효화한다.

.ebextensions 설정

Elastic Beanstalk에 어플리케이션을 올리면 마법처럼 돌아간다고는 하지만,
각 어플리케이션마다 필요한 라이브러리를 모두 설치해 둘 순 없다.
그래서 .ebextensions 설정을 통해 각 어플리케이션에 맞는 라이브러리 설치와, 서버 설정 변경등이 가능하다.
.ebextensions에 대한 설명은 아마존의 컨테이너 맞춤 설정 안내(http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers.html)를 참조하면 된다.
이 글에서는 yum 패키지 업데이트와 라이브러리 설치, 배포 hook 설정 변경과 아파치 서버 변경을 다룬다.

01_yum_update.config

yum 패키지를 업데이트 한다.
commands:
  yum_updates: 
    command: "yum --security update -y"


02_package_update.config

필요한 yum 패키지를 설치한다.
packages키를 이용해도 되지만, 충돌이 일어날 경우 command키를 이용한 설치도 한 방법이다.
commands:
  yum_package_updates: 
    command: "yum install python-devel python-pip libtiff-devel libjpeg-turbo-devel libzip-devel freetype-devel lcms2-devel tcl-devel php -y --skip-broken"


03_pre_requirements.config

Elastic Beanstalk에 파이썬 어플리케이션을 업로드 하면,
requirements.txt파일을 찾아 필요한 파이썬 라이브러리를 자동으로 설치해 준다.
그런데 간혹 한번에 설치가 안되어 나누어 설치해야 하는 라이브러리가 있다.
몇몇 라이브러리를 설치할때 pip에서 발생하는 문제로 미리 설치할 라이브러리를 pre_requirements.txt에 넣어두고 먼저 설치하면 문제없이 설치된다.
다만 pre_requirements.txt 파일을 먼저 설치하려면 배포 hook코드를 변경해야 한다.
files:
  "/opt/elasticbeanstalk/hooks/appdeploy/pre/03deploy.py":
    mode: "000755"
    owner: root
    group: users
    content: |
      #!/usr/bin/env python
      import os
      from subprocess import call, check_call
      import sys
      sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
      import config


      def install_virtualenv():
          # If python 2.7 is installed, make the virtualenv use it. Else use the default system 2.6
          if config.get_python_version() == '2.7':
              cmd = 'virtualenv -p /usr/bin/python27 {0}'
          else:
              cmd = 'virtualenv {0}'

          return_code = call(cmd.format(config.APP_VIRTUAL_ENV), shell=True)

          if return_code != 0:
              print "WARN: error running '%s'" % cmd


      def install_dependencies():
          pre_requirements_file = os.path.join(config.ON_DECK_DIR, 'app', 'pre_requirements.txt')
          requirements_file = os.path.join(config.ON_DECK_DIR, 'app', 'requirements.txt')
          if os.path.exists(pre_requirements_file):
              check_call('%s install --use-mirrors -r %s' % (os.path.join(config.APP_VIRTUAL_ENV, 'bin', 'pip'), pre_requirements_file), shell=True)
          if os.path.exists(requirements_file):
              # Note, we're sharing the virtualenv across multiple deploys, which implies
              # this is an additive operation. This is normally not a problem and is done
              # to minimize deployment time (the requirements are not likely to drastically
              # change between deploys).
              check_call('%s install --use-mirrors -r %s' % (os.path.join(config.APP_VIRTUAL_ENV, 'bin', 'pip'), requirements_file), shell=True)


      def main():
          try:
              install_virtualenv()
              install_dependencies()
          except Exception, e:
              config.emit_error_event(config.USER_ERROR_MESSAGES['badrequirements'])
              config.diagnostic("Error installing dependencies: %s" % str(e))
              sys.exit(1)

      if __name__ == '__main__':
          config.configure_stdout_logger()
          main()


04_wsgi.config

아파치 서버 설정 파일을 입맛에 맞게 변경한다. wsgi.conf 파일을 .ebextensions 폴더에 넣어두고,
wsgi.config 훅에 아래 코드를 넣으면 서버로 설정을 복사한다.
container_commands:
  replace_wsgi_config:
    command: "cp .ebextensions/wsgi.conf /opt/python/ondeck/wsgi.conf"


wsgi.conf

캐쉬와 gzip압축등 설정을 담았다.
# LoadModule wsgi_module modules/mod_wsgi.so
WSGIPythonHome /opt/python/run/baselinenv
WSGISocketPrefix run/wsgi
WSGIRestrictEmbedded On

<VirtualHost *:80>
###############
# TYPES FIX #
###############
AddType text/css .css
AddType text/javascript .js

############################
# IE 11 Prevent Cache      #
############################
BrowserMatch "MSIE 11.0;" IE11FOUND
BrowserMatch "Trident/7.0;" IE11FOUND
# FileETag None
Header unset ETag env=IE11FOUND
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"  env=IE11FOUND
Header set Pragma "no-cache" env=IE11FOUND
Header set Expires "Thu, 24 Feb 1983 02:50:00 GMT" env=IE11FOUND

####################################
# Serve Pre-Compressed statics #
####################################
RewriteEngine On
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.(html|css|js|json|woff) $1\.$2\.gz [QSA]

# Prevent double gzip and give the correct mime-type
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1,E=FORCE_GZIP]
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1,E=FORCE_GZIP]
RewriteRule \.html\.gz$ - [T=text/html,E=no-gzip:1,E=FORCE_GZIP]
RewriteRule \.json\.gz$ - [T=application/json,E=no-gzip:1,E=FORCE_GZIP]
RewriteRule \.woff\.gz$ - [T=application/x-font-woff,E=no-gzip:1,E=FORCE_GZIP]

Header set Content-Encoding gzip env=FORCE_GZIP

#######################
# GZIP COMPRESSION #
######################
SetOutputFilter DEFLATE
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml text/javascript application/x-javascript application/x-httpd-php
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip
Header append Vary User-Agent env=!dont-vary

################################
# Leverage browser caching #
###############################
<FilesMatch ".(ico|pdf|jpg|jpeg|png|gif|html|htm|xml|txt|xsl)$">
Header set Cache-Control "max-age=31536050"
</FilesMatch>

############################
# CDN Rewrite Setting   #
############################
# Header set Access-Control-Allow-Origin: "*"
# UseCanonicalName On
# Don't redirect if the static hostname(s) loops back.
# RewriteCond %{HTTP_HOST} !^static\.
# Include only those static file extensions that we want to off-load.
# RewriteCond %{REQUEST_FILENAME} ^/.*\.(html|xml|txt|zip|gz|tgz|swf|mov|wmv|wav|mp3|pdf|svg|otf|eot|ttf|woff|jpg|jpeg|png|gif|ico|css|js|json)$
# RewriteRule /static/(.*)? http://static.dorajistyle.pe.kr/$1 [redirect=permanent,last]

#########################
# WSGI configuration #
#########################

WSGIScriptAlias / /opt/python/current/app/application.py

<Directory /opt/python/current/app/>
# Order allow,deny
# Allow from all
Require all granted
</Directory>

WSGIDaemonProcess wsgi processes=1 threads=15 display-name=%{GROUP} \
python-path=/opt/python/current/app:/opt/python/run/venv/lib/python2.7/site-packages user=wsgi group=wsgi \
home=/opt/python/current/app
WSGIProcessGroup wsgi
# WSGIScriptReloading On
</VirtualHost>


배포 스크립트.


deploy.sh

static폴더를 최적화하고, DB스키마가 변경되었을 경우 업데이트 하며, 필요한 파일만 압축하여 aws에 올린다.
optimize_static.sh와 upload_to_aws.py이 중요하다.
#!/bin/bash
STARTTIME=$(date +%s)
./optimize_static.sh
rm *.zip
prefix=$(sed -n '/^PREFIX/ s/.*\= *//p' ./application/config/guid.py | tr -d \')
guid=$(sed -n '/^GUID/ s/.*\= *//p' ./application/config/guid.py | tr -d \')
name="$prefix-$guid"
zip -r $name * ./.ebextensions/* -x ./.git\* ./.idea\* ./docs\* ./node_modules\* ./alembic\* ./tests\* ./images\* *.zip  *.DS_Store  ./application/frontend/static/\*
zip_file=$name'.zip'
echo "$zip_file"
echo -e "Do you want to upgrade alembic schema? (Yes/No) : \c"
read ANSWER
if [ "$ANSWER" == "Yes" ]
then
    alembic revision --autogenerate -m "Alembic initilized boilerplate tables."
fi
echo -e "Do you want to update schema? (Yes/No) : \c"
read ANSWER
if [ "$ANSWER" == "Yes" ]
then
    alembic upgrade head
fi
echo -e "Did you reviewed source and confirmed running status? (Yes/No) : \c"
read ANSWER
if [ "$ANSWER" == "Yes" ]
then
    python2 upload_to_aws.py $name
else
    echo "Checking status and trying to deploy again."
fi
ENDTIME=$(date +%s)
echo "$name"
echo "It takes $(($ENDTIME - $STARTTIME)) seconds to complete this task..."


optimize_static.sh

guid를 생성하고 총 4개까지 히스토리를 남긴다. 혹시 배포가 잘못되어 롤백을 하게될 경우 이전 4버전까지 롤백이 가능하도록 한다.
테스트 서버에 먼저 배포하여 테스트 하고 문제가 없으면 실 서버에 배포를 하기 때문에 실 서버에서 4버전이나 롤백할 가능성은 상당히 희박하다.
static 파일은 require optimizer를 사용해 하나의 js와 하나의 css파일로 합치고, sed를 이용해 디버깅을 위해 사용하던 로그 코드와 공백을 날려 용량을 줄인다.
그리고 각 파일을 gzip으로 압축하여 용량을 다시 한번 줄인다.
#!/bin/bash
guid=$(uuidgen | tr -d '\n-' | tr '[:upper:]' '[:lower:]')
guid=${guid:0:8}
today=$(date '+%Y%m%d')
guid=$today'-'$guid
echo "$guid"
extremely_very_old_guid=$(sed -n '/^VERY_OLD_GUID/ s/.*\= *//p' ./application/config/guid.py)
sed -i "s/^EXTREMELY_VERY_OLD_GUID = .*/EXTREMELY_VERY_OLD_GUID = $extremely_very_old_guid/" ./application/config/guid.py
very_old_guid=$(sed -n '/^OLD_GUID/ s/.*\= *//p' ./application/config/guid.py)
sed -i "s/^VERY_OLD_GUID = .*/VERY_OLD_GUID = $very_old_guid/" ./application/config/guid.py
old_guid=$(sed -n '/^GUID/ s/.*\= *//p' ./application/config/guid.py)
sed -i "s/^OLD_GUID = .*/OLD_GUID = $old_guid/" ./application/config/guid.py
sed -i "s/^GUID = .*/GUID = '$guid'/" ./application/config/guid.py
cd './application/frontend/compiler/'
grunt static
grunt --gruntfile Gruntfile_uncss.js
cd '../../..'
cd './optimizer'
node ./r.js -o build.js
cd "../"
sed -i -r "s/(\ ?|\ +),(\ ?|\ +)[a-zA-Z]\.log(Error|Json|Object|Trace|Debug|Info|Warn)(\ ?|\ +)\([^)]*\)(\ ?|\ +),(\ ?|\ +)/,/g" ./application/frontend/static-build/js/app.js
sed -i -r "s/(\ ?|\ +),(\ ?|\ +)[a-zA-Z]\.log(Error|Json|Object|Trace|Debug|Info|Warn)(\ ?|\ +)\([^)]*\)(\ ?|\ +),?(\ ?|\ +);/;/g" ./application/frontend/static-build/js/app.js
sed -i -r "s/(\ ?|\ +),?(\ ?|\ +)[a-zA-Z]\.log(Error|Json|Object|race|Debug|Info|Warn)(\ ?|\ +)\([^)]*\)(\ ?|\ +),?(\ ?|\ +);//g" ./application/frontend/static-build/js/app.js
sed -i -r "s/(\ ?|\ +),?(\ ?|\ +)[a-zA-Z]\.log(Error|Json|Object|race|Debug|Info|Warn)(\ ?|\ +)\([^)]*\)(\ ?|\ +),?(\ ?|\ +);?/\n/g" ./application/frontend/static-build/js/app.js

cd './application/frontend/static-build/locales'
find . -name '*.json' -exec sed -i '/^\s∗\/\//d' {} \;
find . -name '*.json' -exec sed -i 's/^[ \t]*//g; s/[ \t]*$//g;' {} \;
find . -name '*.json' -exec sed -i ':a;N;$!ba;s/\n/ /g' {} \;
find . -name '*.json' -exec sed -i 's/\"\s*:\s*\"/\":\"/g' {} \;
find . -name '*.json' -exec sed -i 's/\"\s*,\s*\"/\",\"/g' {} \;
find . -name '*.json' -exec sed -i 's/\s*{\s*/{/g' {} \;
find . -name '*.json' -exec sed -i 's/\s*}\s*/}/g' {} \;
cd '../..'
gzip -r --best ./static-build
rename .gz '' `find static-build -name '*.gz'`


upload_to_aws.py

보토를 이용해 Elastic Beanstalk을 업데이트 한다. 배포가 끝나면 guid를 검사하여 오래된 버전 소스를 삭제한다.
static파일 업로드에서 눈여겨 볼 점은 key에 Content_Encoding 메타 데이터를 gzip으로 해 주어야 하는 것이다.
이는 위의 optimize static에서 이미 gzip으로 압축했기 때문이다.

# coding=UTF-8
"""
    application.util.__init__
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
    by dorajistyle

    __init__ module

"""
from Queue import Queue
import logging
import os
import string
import boto
from boto.beanstalk import connect_to_region
import sys
# import time
from application.config.aws import AWS_STATIC_S3_BUCKET_NAME, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, \
    AWS_ELASTIC_BEANSTALK_REGION, AWS_ELASTIC_BEANSTALK_APP_NAME, AWS_ELASTIC_BEANSTALK_ENVIRONMENT_ID, \
    AWS_ELASTIC_BEANSTALK_ENVIRONMENT_NAME, AWS_ELASTIC_BEANSTALK_S3_BUCKET_NAME
from application.config.guid import OLD_GUID, VERY_OLD_GUID, PREFIX_GUID, EXTREMELY_VERY_OLD_GUID
from application.properties import STATIC_GUID
from threading import Thread
logging.basicConfig()
logger = logging.getLogger()


def log_exception(text):
    logger.error(msg=text)

q = Queue()
# source directory
sourceDir = 'application/frontend/static-build/'
# destination directory name (on s3)
destDir = STATIC_GUID+'/'

conn = boto.connect_s3(AWS_ACCESS_KEY_ID,
                       AWS_SECRET_ACCESS_KEY)
bucket = conn.get_bucket(AWS_STATIC_S3_BUCKET_NAME)
eb_bucket = conn.get_bucket(AWS_ELASTIC_BEANSTALK_S3_BUCKET_NAME)
keys = list()
old_keys = list()
eb_keys = list()
for key in bucket.list():
    keys.append(key.name)
for key in eb_bucket.list():
    eb_keys.append(key.name)
eb = connect_to_region(AWS_ELASTIC_BEANSTALK_REGION,
                       aws_access_key_id=AWS_ACCESS_KEY_ID,
                       aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
uploadDirNames = []
uploadFileNames = []
for path in os.listdir( sourceDir ):
    if not os.path.isfile(os.path.join( sourceDir, path)):
        uploadDirNames.append(path+'/')


for (sourceDir, dirnames, filenames) in os.walk(sourceDir):
    for subDir in dirnames:
        # print('dirname:'+ subDir)
        for (subDir, sub_dirnames, subfilenames) in os.walk(sourceDir+subDir):
            for subfilename in subfilenames:
                sub_path = string.replace(subDir, sourceDir, '')
                uploadFileNames.append(os.path.join(sub_path, subfilename))
    uploadFileNames.extend(filenames)
    break


def percent_cb(complete, total):
    sys.stdout.write('.')
    sys.stdout.flush()


def upload_deploy(source_path, dest_path):
    """
    Upload static files to S3 bucket.
    :return:
    """

    try:
        dest_path = dest_path.encode('utf-8')
        key = eb_bucket.new_key(dest_path)
        key.set_contents_from_filename(source_path,
                                       cb=percent_cb, num_cb=10)
    except BaseException as be:
        log_exception(be)
        return False
    return True


def upload_static(source_path, dest_path):
    """
    Upload static files to S3 bucket.
    :return:
    """

    try:
        dest_path = dest_path.encode('utf-8')
        key = bucket.new_key(dest_path)
        # if key.name.endswith(('.gz', '.gzip')):
        key.set_metadata('Content-Encoding', 'gzip')
        key.set_contents_from_filename(source_path,
                                       cb=percent_cb, num_cb=10)
    except BaseException as be:
        log_exception(be)
        return False
    return True


def worker():
    while True:
        item = q.get()
        if item['source_path'] == item['dest_path']:
            upload_deploy(item['source_path'], item['dest_path'])
        else:
            upload_static(item['source_path'], item['dest_path'])
        q.task_done()
        print 'Uploading %s to Amazon S3 bucket %s' % \
              (item['source_path'], item['dest_path'])

# threads = []
if len(sys.argv) == 2:
    eb_app = eb.describe_applications(application_names=AWS_ELASTIC_BEANSTALK_APP_NAME)
    versions = eb_app['DescribeApplicationsResponse']['DescribeApplicationsResult']['Applications'][0]['Versions']
    # if len(versions) > 2:
    #     versions = versions[:2]
    latest_version = PREFIX_GUID.replace('\'', '')+'-'+OLD_GUID.replace('\'', '')
    very_old_version = PREFIX_GUID.replace('\'', '')+'-'+VERY_OLD_GUID.replace('\'', '')
    extremely_very_old_version = PREFIX_GUID.replace('\'', '')+'-'+EXTREMELY_VERY_OLD_GUID.replace('\'', '')
    try:
        if latest_version in versions:
            versions.remove(latest_version)
        if very_old_version in versions:
            versions.remove(very_old_version)
        if extremely_very_old_version in versions:
            versions.remove(extremely_very_old_version)

        for key in bucket.list(prefix=OLD_GUID.replace('\'', '')):
            keys.remove(key.name)
        for key in bucket.list(prefix=VERY_OLD_GUID.replace('\'', '')):
            keys.remove(key.name)
        for key in bucket.list(prefix=EXTREMELY_VERY_OLD_GUID.replace('\'', '')):
            keys.remove(key.name)

        for eb_key in eb_bucket.list(prefix=latest_version):
            eb_keys.remove(eb_key.name)
        for eb_key in eb_bucket.list(prefix=very_old_version):
            eb_keys.remove(eb_key.name)
        for eb_key in eb_bucket.list(prefix=extremely_very_old_version):
            eb_keys.remove(eb_key.name)

        file_name = sys.argv[1]
        zip_file = file_name + '.zip'
        for i in range(8):
            t = Thread(target=worker)
            t.daemon = True
            t.start()
        item = {}
        item['source_path'] = zip_file
        item['dest_path'] = zip_file
        q.put(item)
        for filename in uploadFileNames:
            source_path = os.path.join(sourceDir + filename)
            dest_path = os.path.join(destDir, filename)
            item = {}
            item['source_path'] = source_path
            item['dest_path'] = dest_path
            q.put(item)
        q.join()
        eb.create_application_version(AWS_ELASTIC_BEANSTALK_APP_NAME, version_label=file_name,
                                      description=None, s3_bucket=AWS_ELASTIC_BEANSTALK_S3_BUCKET_NAME, s3_key=zip_file)
        eb.update_environment(environment_id=AWS_ELASTIC_BEANSTALK_ENVIRONMENT_ID,
                              environment_name=AWS_ELASTIC_BEANSTALK_ENVIRONMENT_NAME,
                              version_label=file_name)
        bucket.delete_keys(keys)
        eb_bucket.delete_keys(eb_keys)
        for version in versions:
            eb.delete_application_version(application_name=AWS_ELASTIC_BEANSTALK_APP_NAME, version_label=version, delete_source_bundle=False)
    except BaseException as be:
        print(str(be))
        if latest_version is not None:
            eb.update_environment(environment_id=AWS_ELASTIC_BEANSTALK_ENVIRONMENT_ID,
                                  environment_name=AWS_ELASTIC_BEANSTALK_ENVIRONMENT_NAME,
                                  version_label=latest_version)
    # print('eb application' + str(eb.retrieve_environment_info(environment_id=AWS_ELASTIC_BEANSTALK_ENVIRONMENT_ID,
    #                       environment_name=AWS_ELASTIC_BEANSTALK_ENVIRONMENT_NAME)))
    print('AWS Elastic Beanstalk updated.')
print('Bye Bye!')



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

Nginx 서버에서 FastCGI를 이용하여 PHP 설정하기.


필요 패키지 설치 (Arch linux 기준)

  • sudo pacman -S php
  • sudo pacman -S php-fpm
  • sudo pacman -S php-sqlite

/etc/php/php.ini 수정

  1. open_basedir = list_base_directories_which_contain_PHP_files
  2. uncomment
    extension=sqlite3.so
    extension=openssl.so

    extension=sqlite3.so는 php-fpm을 위해 필요하다.
    extension=openssl.so는 https로 요청을 보낼 때 필요하다.

nginx.conf

http{
server{
location ~ \.php$ {
root /root_directory_of_php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# fastcgi_pass 127.0.0.1:8050;
fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_param DOCUMENT_ROOT /root_directory_of_php/inilite_php;
include fastcgi_params;
}
}
}


nginx 설정 오류 확인

sudo nginx -t

참조

https://wiki.archlinux.org/index.php/nginx#PHP_implementation
http://www.sitepoint.com/setting-up-php-behind-nginx-with-fastcgi/



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

인터넷 익스플로러 9 이하에서 CORS(Cross-origin resource sharing) 설정.

정적인(static) 파일은 보통 CDN(Contents Delivery Network)과 연결하여 사용자에게 빠르게 전달한다.
사용자 입장에선 빠르게 콘텐츠를 받아볼 수 있어 좋고,
관리자 입장에선 서버에 부담을 줄여줘서 좋다.
그러나 외부 CDN을 이용할 땐 주의해야 한다.
인터넷 익스플로러 대마왕이 CDN을 편히 쓰도록 가만히 놔두질 않기 때문이다.
만약 스타일 시트를 CDN에 올려놨다면, 인터넷 익스플로러에서 처참하게 망가진 화면을 만나게 될 것이고,
Ajax로 CDN 서버에 요청을 한다면 404 오류코드(파일은 내가 처리했다. 다음은 너 차레야라는 뜻.)를 만나게 된다.
이것은 재앙이며, 개발자에겐 악몽을 선사한다.

우리나라는 1999년 전자서명법을 시행하면서 액티브X를 중심으로 하는 공인인증제가 도입됐다.
이것이 인터넷 익스플로러 대마왕의 힘을 키워준 것이 되었고,
웹 개발자(특히 한국 개발자)는 새천년 밀레니엄의 시작과 함께 인터넷 익스플로러 대마왕과 힘겨운 싸움을 이어와야 했다.
최근에는 인터넷 익스플로러에서 보안 결함이 발견되어 영국과 미국 정부에서 인터넷 익스플로러를 쓰지 말라는 권고를 내리기도 했었다.
(http://www.telegraph.co.uk/technology/microsoft/10793272/Dont-use-Internet-Explorer-warns-US-government.html)
물론 이 문제가 패치 되긴 했지만(http://techcrunch.com/2014/05/01/microsoft-patches-latest-internet-explorer-security-flaw-even-for-xp-users),
인터넷 익스플로러는 여전히 골칫거리여서,
'인터넷 익스플로러 쓰지 마세요.'(http://donotuseie.com)라는 사이트가 있을 정도다.

마음 같아서는 인터넷 익스플로러를 무시하고 개발하고 싶다.
그러나, 한국에선 인터넷 익스플로러가 갑이다.
인터넷 익스플로러에서만 돌아가는 웹사이트가 수두룩하기 때문이다.
'한국 사람들은 인터넷 익스플로러를 써요. 법이거든요.'(http://www.zdnet.com/south-koreans-use-internet-explorer-its-the-law-7000022827)라는 기사에서도 볼 수 있듯,
우리나라는 인터넷 익스플로러 사용자 인구가 많다.
게다가 10부터는 그나마 좀 나은데, 우리나라는 8을 제일 많이 쓴다.
statcounter 작년 5월부터 올해 5월까지 통계를 뽑아보니 한숨이 나온다.

브라우저 이용 현황, 한국-'인터넷 익스플로러(IE) 9이하에서  CORS 설정'

그럼 전 세계적으로는 어떤 브라우저를 많이 쓸까?

브라우저 이용 현황, 전세계-'인터넷 익스플로러(IE) 9이하에서  CORS 설정'

크롬이 압도적이고, 다음은 파이어폭스다.
하지만 한국의 개발자가 웹 어플리케이션을 만들려면, IE8 이상은 지원해야 된다.
대한민국은 인터넷 익스플로러 강국이니까.

인터넷 익스플로러(IE) 9이하에서 CORS 설정.

CDN서버에 CORS 설정을 해 두고, 아래 코드를 적용하면 된다.

우선 CSS를 제대로 보여주기 위한 Respond.js 설정이다.

마크업

여기에서 static_path는 CDN서버의 주소이다.
<!DOCTYPE html>
...
<html><head>
<!--[if lt IE 9]><>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<link href="#{static_path}/js/vendor/respond-proxy.html" id="respond-proxy", rel="respond-proxy">
<link href="/ie/respond/respond.proxy.gif" id="respond-redirect", rel="respond-redirect">
<script src="/ie/respond/respond.proxy.js"></script>
<![endif]--></head>...</html>


서버단 flask

/ie로 요청이 들어오면, 어플리케이션의 루트안에 ie폴더에서 파일을 찾아 응답한다.
@app.route('/ie/')
def base_static(filename):
print('app root path '+str(app.root_path))
print('app filename '+str(filename))
return send_from_directory(app.root_path + '/ie/', filename)

그리고 jQuery ajaxTransport XDomainRequest(https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest)를 다운받아 jquery 다음에 불러 놓으면,
인터넷 익스플로러에서 자동으로 CORS처리를 해준다. 내겐 이게 제일 간편하고 좋았다.

인터넷 익스플로러의 횡포가 계속된다면 '한국에서 인터넷 익스플로러를 무찌를 레이드 파티 구합니다.'라는 공고가 올라올지도...?

참조



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

git 저장소에 변화가 생기면, 서버에 자동으로 업데이트하는 스크립트.


소스가 변경될 때 마다, 라이브서버에 소스를 업데이트 하는 일은 참 귀찮은 일이다.
그래서 보통 cron을 이용해 서버에 소스 자동 업데이트를 하곤 한다.
이번에도 cron을 이용해 자동 업데이트를 구축하려다가 한가지 문제에 부딪혔다.
crontab에서 스크립트를 돌릴경우 상대경로를 쓰지 못한다는 거다.
그래서 비슷한 걸 찾아 헤매다가 shell-jobs를 발견했고,
이를 이용해 git 저장소가 갱신될 때마다 서버를 자동 업데이트하도록 구축했다.


작동 순서

  1. shell-jobs 데몬 실행.
  2. shell-jobs에서 일정 시간마다 ~/update.sh를 호출.
  3. ~/update.sh에서 원격 저장소를 업데이트하고 변경사항이 있다면 update_platform.sh를 호출.
  4. update_platform.sh에서 소스를 업데이트하고 서버를 재구동.

shell-jobs(https://github.com/azer/shell-jobs)

설치

npm install -g shell-jobs

설정파일 작성

update.jobs
~/update.sh > ~/cron.log # => 10 minutes

shell-jobs 데몬으로 구동

shell-jobs update.jobs -d

리눅스 시동시에 자동으로 구동되도록 하려면, /etc/rc.local파일에도 위 코드를 추가한다.

update.sh

원격 저장소를 업데이트하고 git diff를 통해 로컬과 다른점을 검사한다.
grep -v 뒤에는 로컬 변경을 무시할 파일명을 넣는다.
만약 원격 저장소와 다른 점이 있다면 update_platform.sh를 실행한다.
#!/bin/sh
cd /home/project
git remote update
diff=$(git diff remotes/origin/master master | grep -v <무시할 변경사항>)
if ["$diff" == ""]
then
echo "no diffs"
else
echo "have diffs"
~/update_platform.sh
fi


update_platform.sh

소스를 최신으로 업데이트하고, 서버를 재구동하는 스크립트.
sed를 이용해 debug플래그와 project.wsgi파일을 변경하기 때문에,
git reset --hard로 로컬 변경사항을 무시한다.
#!/bin/sh
cd /home/project
git checkout master
git reset --hard master
git pull
pip2 install -r requirements.txt
alembic revision --autogenerate -m "Alembic initilized boilerplate tables."
alembic upgrade head
sed -i "s/^DEBUG = .*/DEBUG = False/" ./application/config/debug_flag.py
sed -i "s/^sys.path.insert.*/sys.path.insert\(0, '\/home\/project'\)/" ./project.wsgi
chown me -R .
~/restart_server.sh


resteart_server.sh

간혹 서버를 직접 재구동하기도 하니, 서버 재구동용 스크립트는 따로 작성한다.
#!/bin/sh
service apache2 restart



by


Tags : , , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

android kitkat을 탑제한 구글 레퍼런스 폰. nexus5.


휴대폰 분실로 갑작스럽게 폰을 바꿨다.
쓰지도 않는 제조사와 통신사 앱이 잔뜩 깔려있는게 피곤해서 선택한 nexus5.
취향따라 설정해 쓰는 재미가 쏠쏠하다.


박스-'nexus5'


Arch Linux에 android sdk 설치하기.

sudo yaourt -S android-sdk
sudo yaourt -S android-udev
sudo yaourt -S android-sdk-platform-tools

environment path를 설정한다.
android를 실행시켜서 sdk 받음

nexus5 USB 마운트 하기

MTP설정

  1. nexus5 설정 메뉴로 이동
  2. 저장소(storages) 선택
  3. 우측 상단의 메뉴 버튼 선택
  4. USB 컴퓨터 연결 선택
  5. MTP 체크

USB 디버깅 설정

  1. nexus5 설정 메뉴로 이동
  2. About Phone(휴대전화 정보) 메뉴로 이동
  3. Built Number(빌드 번호) 를 여러번 탭
  4. 다시 nexus5 설정 메뉴로 이동
  5. Developer Options(개발자 옵션) 선택
  6. USB Debugging(USB 디버깅) 체크

adb에서 nexus5를 장치로 인식하지 못할 때.

sudo adb kill-server
sudo adb devices

lsusb로 연결 확인 (케이블 문제로 연결이 안될수도 있으니 확인한다.)

fastboot devices에서 nexus5를 장치로 인식하지 못할 때.

  1. 넥서스5 전원을 끈다.
  2. Volume Up(소리크게), Volumn Down(소리 작게), Power(전원) 버튼을 동시에 누른다.

adeb devices에 nexus5가 잡혔는지 확인 후 다음 커맨드를 입력한다.

fastboot oem unlock
볼륨키로 YES를 선택한 후 전원키를 눌러 확인한다.

fastboot reboot 커맨드로 nexus5를 재부팅 한다.

nexus5에 커스텀 리커버리 TWRP 설치

fastboot flash recovery ~/openrecovery-twrp-2.7.0.0-hammerhead.img

TWRP 실행

  1. 볼륨키로 Rstart Bootload 선택한다.
  2. 전원 버튼을 누른다.
  3. 부트로더가 reload 된다.
  4. 볼륨키로 Recovery Mode를 선택한다.
  5. 전원 버튼을 누른다.

nexus5에 커스텀 롬 설치

설치한 커스텀 롬은 carbon(https://carbonrom.org/downloads/?device=hammerhead&type=nightly)으로 깔끔해서 마음에 든다.

  1. Wipe 선택
  2. Dalvik Cache, System, Data, and Cache 선택
  3. Swipe to Wipe
  4. TWRP 메인 메뉴로 이동
  5. Install
  6. Custom Rom 설치
  7. Gapps 설치
  8. Reboot And System

nexus5 루팅하기

nexus 5를 리커버리 모드로 켜고, 컴퓨터에연결된 상태에서 아래 커맨드를 실행한다.
adb push UPDATE-SuperSU-vX.XX.zip /sdcard/
1. TWRP 메인 메뉴로 이동
2. Install
3. SuperSu 설치
4. Reboot And System
금융어플을 사용할 경우 spapa님의 뱅킹 SuperSu(http://spapa1004.tistory.com/188)를 받아 설치하면 된다.


nexus5 루팅상태로 은행 앱 사용하기 (http://cafe.naver.com/develoid/402823)

develoid의 팁을 참조하여 적용하였으나, 루팅감지를 회피하지 못한다.
1. SELinux Mode Changer 설치
2. PERMISSIVE로 선택
3. 재부팅
4. Cydia Substrace 설치
5. Link Substrace Files 선택
6. 재부팅
7. RootCloak Plus 설치
8. Add/Remove에서 루팅감지 회피할 앱 선택
9. 재부팅


nexus5 유용한 앱


nexus5 팁


참조



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

안드로이드 기기에서 크롬 모바일 브라우저 디버깅하기.


개발자 도구가 잘 갖추어진 크롬을 개발환경에서 주로 쓴다.
안드로이드 기기에서 크롬 모바일 브라우저를 사용한다면, 모바일 환경에서도 크롬 개발자 도구로 디버깅할 수 있다.


안드로이드 기기(스마트폰 등) 설정

  • 설정 이동
  • 모바일 기기 개발자 도구(developer options) 이동
  • USB 디버깅(USB Debugging) 체크

기기와 PC를 연결한다.


PC 설정

  • 크롬 브라우저 구동
  • 주소창에 chrome://inspect 입력
  • discover USB devices 체크

이제 기기가 연결되고, 모바일 크롬 브라우저에 띄워놓은 창을 크롬 개발자 도구(developer tool)로 디버깅 할 수 있다.


또한 포트 포워딩(port forwarding)기능을 이용하면, PC에서 띄운 서버가 모바일에서도 접속된다.
포트 포워딩(port forwarding)버튼을 누르면 창이 나오는데, 이곳에서 값을 넣고 Enable port forwarding을 체크하여 설정한다.
예를 들어 PC에 서버를 localhost:8080으로 띄우고, 아래처럼 설정하면 모바일에서 localhost:8080으로 PC서버에 접속된다.
8080 localhost:8080


참조

https://developers.google.com/chrome-developer-tools/docs/remote-debugging



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

스마트폰 잃어버렸을 때 원격에서 잠금‧초기화. Android device manager.

요즘 대부분의 사람이 스마트폰을 이용한다.
그만큼 도난‧분실도 잦은데 막상 스마트폰을 잃어버린다면, 하드웨어뿐 아니라 소프트웨어도 함께 분실한다.
중요한 자료가 스마트폰에 담겨있다면?
주소록의 연락처가 모두 유출된다면?
공인인증서가 남의 손에 넘어간다면?
가뜩이나 휴대폰 잃어버린 것도 서러운데, 정보까지 유출될까 걱정해야 한다니!

구글에서는 이를 어느 정도 해소해줄 방법을 제공한다.
안드로이드폰은 구글 계정과 동기화할 수 있는데, 동기화에 성공하면 안드로이드 기기관리자를 통해 스마트폰을 원격에서 제어할 수 있다.

현재 위치를 추적하고, 벨을 울리도록 하며, 화면도 잠그고, 기기의 초기화까지 제공한다.
단, 휴대폰에 원격에서 접근할 수 있는 상태(전원이 켜져 있고, WIFI나 데이터네트워크가 가능한 상태)여야만 한다.
온라인에서만 작동한다는 것은 아쉽지만, 스마트폰 분실‧도난에 대비하여 미리 설정해 둔다면, 기기가 없어졌을 때 발 빠른 조치를 할 수 있다.
이걸 미리 알았다면 어제 휴대폰을 잃어버리자마자 조치를 했을 텐데, 늦게 알게 되어 아쉽다.

안드로이드 기기 관리자 (https://www.google.com/android/devicemanager)


안드로이드 기기 관리자는 휴대폰의 전원이 꺼져있다면 방법이 없지만, 오프라인 상태의 스마트폰 이동 경로를 추적하는 방법이 있다.
스마트폰의 지난 이동 경로를 보려면 구글 지도의 지난 이동 경로 보기를 이용하는 것이다.
지난 이동 경로를 본다고 해도 휴대폰에 아무런 조치를 할 순 없지만, 휴대폰이 꺼져있는 경우 마지막 위치를 확인하는 데 도움이 된다.
구글 지난 경로 보기-'안드로이드 기기 지난 경로 보기'

나의 구글 지난 경로 보기로 다시 본 결과, 나의 스마트폰은 분실지점에서 45분가량 주인을 기다리다가, 주인이 휴대폰을 찾으러 그 장소에 다시 도착하기 10분 전부터 이동을 시작했다.
이동속도로 보면, 휴대폰은 자전거로 이동한 듯 보인다. 마지막 신호는 도림천에서 끊겼다.

혹시 2014년 04월 25일 오전 9시 55분경 서강대교 인근 한강변 의자에서 휴대폰을 습득하시고, 한강변과 안양천을 따라 자전거를 타신 후, 2014년 04월 25일 오전 10시 56분경 도림천에 도착하신 분이 이 글을 보신다면 연락 주시면 좋겠다.
약 10KM를 달리는데 45분가량 걸린 걸로 추측건대 천천히 라이딩을 즐기시는 여유로운 분으로 생각된다. :D

구글 지도 지난 경로 보기 (https://maps.google.com/locationhistory)



이동전화를 분실하여 통신사에 분실‧도난 신고를 했다면, 이동전화 단말기 자급제 사이트에서 신고가 제대로 되었는지 IMEI 번호를 통해 확인할 수 있다.
이동전화 단말기 자급제(http://www.checkimei.kr/search/search_1.php)

분실된 휴대폰을 찾고 싶다면, 아래의 사이트에서 확인할 수 있다.


분실된 스마트폰 찾기



by


Tags : , , , , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

OpenSSL 라이브러리에서 서버에 저장된 중요 메모리 데이터가 노출되는 HeartBleed 보안 업데이트 방법


한국 인터넷침해대응센터(http://krcert.or.kr)의 보안공지에 아래 내용의 OpenSSL 취약점(HeartBleed) 대응 방안 권고가 올라와 있다.

통신 구간 암호화를 위해 많이 사용하는 OpenSSL 라이브러리에서 서버에 저장된 중요 메모리 데이터가 노출되는 HeartBleed라고 명명된 심각한 버그가 발견되어 시스템 및 소프트웨어에 대한 신속한 취약점 조치를 권고

Yahoo, Google, Facebook, Instagram, Tumblr, Pinterest, Github, Dropbox, AWS 등 OpenSSL HeartBleed취약점에 영향을 받은 서비스가 많은데, 서버 관리자 입장에선 머리가 쭈뼛했겠다.^^;
혹시 운영 중인 서버가 아직 OpenSSL HeartBleed 보안 업데이트가 안 되었다면, 지금이라도 잽싸게 업데이트하자!

  1. 버전 확인

    sudo openssl version -a
    built on 날짜가 2014년 4월 7일 이전이면 취약하므로 시스템 보안업데이트를 진행한다.
  2. 보안 업데이트 설치


    Arch 계열

    pacman -Syu

    Fedora 계열

    yum update

    Ubuntu 계열

    sudo apt-get update
    sudo apt-get dist-upgrade
  3. 재시동

    sudo reboot
  4. 버전 재확인

    sudo openssl version -a
    built on 날짜가 2014년 4월 7일 이후인지 다시 확인한다.
    예) OpenSSL 1.0.1g 7 Apr 2014
    built on: Mon Apr 7 22:24:40 CEST 2014

OpenSSL Heartbleed 보안 업데이트 참고 자료



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

Arch linux 기반 배포판. Manjaro linux 설치 및 설정.


Gentoo기반의 Sabayon 리눅스에서 Asus ux31a의 무선랜을 못 잡는다.
여러 시도를 해보다가 안되서 다른 걸로 갈아타려고 여러 리눅스 배포판을 기웃거렸다.
봐도 봐도 끌리는 건 FreeBSD기반의 GhostBSD와 Arch 기반 Manajro다.
안써본 GhostBSD를 써보려고 이리저리 시도해 봤지만 아쉽게도 ux31과 궁합이 안 맞는지 설치가 되지 않는다.
그래서 결국 익숙한 Manjaro linux를 깔았다.
Ubuntu 보다 민첩하고, gentoo보다 편리한 Manjaro.
나와 궁합이 잘 맞는다.
Arch linux를 별다른 설정 없이 편리하게 사용하도록 만든 Manjaro linux.
그러나 내게 맞는 환경을 만들기 위해선 여기저기 손봐야 할 곳이 많다.
이게 시간이 꽤 걸리는 일이라, 나중을 위해 지금 리눅스 환경을 정리했다.
앞으로 한동안은 OS를 다시 설치할 일이 없겠지만,
재앙은 예고 없이 찾아오는 법이니까.


배포판 이미지 받기

http://sourceforge.net/projects/manjarolinux/files


부팅 가능한 USB 만들기

http://sourceforge.net/projects/manjarolinux/files
UNetbootin(http://unetbootin.sourceforge.net/) - linux,mac,windows
Pendrivelinux(http://www.pendrivelinux.com/) - windows
Image Writer for Windows(https://launchpad.net/win32-image-writer) - windows
http://en.wikipedia.org/wiki/List_of_tools_to_create_Live_USB_systems


USB로 설치.

이미 리눅스 시스템을 사용중인 Encrypt된 파티션을 가진 SSD에 UEFI를 지원하도록 설치.
1. 터미널 실행.
2. Encrypt된 파티션 열기
cryptsetup luksOpen /dev/sdx cryptVG
3. root파티션 포멧하기
mkfs ext4 /dev/mapper/cryptVG-root-partition-name
4. GUI모드로 설치 시작
5. 파티션 설정
* /swap : 없음.
* /boot : ext4
* /boot/efi : vfat
* /root : ext4 (위에서 포멧한 파티션)
* /home : ext4 (포멧하지 않고 마운트만)
6. 설치 진행
7. 설치가 완료되면, 터미널 실행.
8. 설치된 시스템 루트로 chroot
mount -o bind /proc /mount-point-of-installed-root/proc
mount -o bind /dev /mount-point-of-installed-root/dev
mount -o bind /sys /mount-point-of-installed-root/sys
chroot /mount-point-of-installed-root /bin/bash

9. /etc/mkinitcpio.conf 파일에서 HOOKS의 filesystems 앞에 encrypt lvm2 추가.
예시 : HOOKS="base udev autodetect modconf block encrypt lvm2 filesystems keyboard keymap fsck"
10. mkinitcpio 설정 적용.
mkinitcpio -p linux
11. /etc/default/grub 파일에서 GRUB_CMDLINE_LINUX_DEFAULT 옵션 변경
libata.force=noncq : SSD성능 향상,응답 중단 방지 (The libata.force=noncq parameter will prevent SSD lockups and the rootflags option is used for SSD-performance.)
acpi_osi : ux31a에서 기능키 사용
cryptdevice : Encrypt된 파티션 정보
noapic : 인텔의 Advanced Programmable Interrupt Controller를 사용하지 않는다.
acpi=force : acpi를 바이오스 버전에 관계 없이 켠다.
예시 : GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=/dev/sda3:cryptVG quiet libata.force=noncq acpi_osi='!Windows 2012' noapic acpi=force"
12. Grub 설정 적용.
grub-mkconfig -o /boot/grub/grub.cfg
sudo update-grub
13. 재부팅
14. USB 제거


fstab 설정

ssd를 사용할 경우 파티션에 defaults,noatime,discard를 붙인다.
/etc/fstab
tmpfs /dev/shm tmpfs defaults,noatime 0 0
tmpfs /tmp tmpfs defaults,noatime,mode=1777,size=4G 0 0
tmpfs /scratch tmpfs noatime,nosuid,nodev,mode=1777 0 0



로케일 설정

https://wiki.archlinux.org/index.php/locale

/etc/locale.gen
ko_KR.UTF-8 UTF-8
en_GB.UTF-8 UTF-8
es_ES.UTF-8 UTF-8
ja_JP.UTF-8 UTF-8
zh_CN.UTF-8 UTF-8


/etc/locale.conf
LANG=ko_KR.UTF-8
LANGUAGE="ko_KR.UTF-8:es_ES.UTF-8:en_GB.UTF8:en"
LC_COLLATE=ko_KR.UTF-8
LC_CTYPE=ko_KR.UTF-8
LC_MONETARY=ko_KR.UTF-8
LC_NUMERIC=ko_KR.UTF-8
LC_TIME=ko_KR.UTF-8
LC_PAPER=ko_KR.UTF-8
LC_MESSAGES=en_GB.UTF-8


~/.config/locale.conf
LANGUAGE="ko_KR.UTF-8:es_ES.UTF-8:en_GB.UTF8:en"
LANG="ko_KR.UTF-8"
LC_COLLATE=ko_KR.UTF-8
LC_CTYPE=ko_KR.UTF-8
LC_MONETARY=ko_KR.UTF-8
LC_NUMERIC=ko_KR.UTF-8
LC_TIME=ko_KR.UTF-8
LC_PAPER=ko_KR.UTF-8
LC_MESSAGES=en_GB.UTF-8


sudo locale-gen


Pacman 업데이트

pacman
pacman -Syy
pacman -Syu



Manjaro 커널 업데이트

http://wiki.manjaro.org/index.php/Manjaro_Kernels
mhwd-kernel -li
sudo mhwd-kernel -i linux313 rmc



한글 관련 설정


UIM 설정

sudo pacman -S uim

Applications Menu > settings > input method

Global settings
check Specify default IM
Default input method Byeoru
Enable input methods Byeoru only.
Uncheck Enable IM switching by hotkey.
Uncheck Enable input method toggle by hot keys.

Byeoru key bindings 1
Add hangul key to Byeoru on, Byeoru off

~/.xprofile에 IM설정
IM="uim"
export GTK_IM_MODULE=$IM
export XMODIFIERS=@im=$IM
export QT_IM_MODULE=$IM
export XIM=$IM

한글폰트 설치

yaourt -S ttf-alee
yaourt -S xfonts-baekmuk
yaourt -S ttf-unfonts-core
yaourt -S ttf-unfonts-extra
yaourt -S ttf-nanum
yaourt -S ttf-nanumgothic_coding


PDF 한글 나오도록 poppler(PDF rendering library)설치

sudo pacman -S poppler
sudo pacman -S poppler-data

; pdf뷰어 epdfview 설치
sudo pacman -S epdfview

VLC 한글 설정

Pereference -> Subtitles / OSD -> Default encoding 을 Korean(EUC-KR/CP949)로 변경하고 플레이어를 다시 시작한다.


watchdog(프로세스가 죽으면 자동 재시동) 설정

/etc/systemd/system.conf
#RuntimeWatchdogSec=0
RuntimeWatchdogSec=30



어플리케이션 설치


개발용

pacman -S ruby
pacman -S git
pacman -S openssh
pacman -S mariadb
pacman -S apache
pacman -S mod_wsgi2
yaourt -S jdk

nodejs

git clone git://github.com/creationix/nvm.git ~/.nvm
printf "\n\n# NVM\nif [ -s ~/.nvm/nvm.sh ]; then\n\tNVM_DIR=~/.nvm\n\tsource ~/.nvm/nvm.sh\nfi" >> ~/.bashrc
NVM_DIR=~/.nvm
source ~/.nvm/nvm.sh
nvm install v0.10.25
nvm alias default 0.10
nvm use 0.10

권한 설정
sudo chown -R `whoami` ~/.npm
sudo chown -R `whoami` ~/node_modules
sudo chown -R `whoami` /usr/lib/node_modules


루비 경로 설정

~/.xprofile
export PATH=$PATH:~/.gem/ruby/2.1.0/bin:

gvim 설치

pacman -S gvim
플러그인 설치
vim-colorsupport https://aur.archlinux.org/packages/vim-colorsupport/
Vundle vundle-git https://github.com/gmarik/Vundle.vim
NERDTree vim-nerdtree-git https://github.com/scrooloose/nerdtree
ctrip https://github.com/kien/ctrlp.vim
Syntastic vim-syntastic https://github.com/scrooloose/syntastic
EasyMotion vim-easymotion https://github.com/Lokaltog/vim-easymotion

.vimrc
nmap "+gP
imap i
vmap "+y
vmap "+x
syntax on
set wrap
set linebreak
" set spell spelllang=en_GB "
map :set spell! spelllang=en_GB
map :set guioptions-=m:set guioptions-=r:set guioptions-=l:set guioptions-=L:set guioptions-=T:redraw!
map :set guioptions+=m:set guioptions+=r:set guioptions+=l:set guioptions+=L:set guioptions+=T:redraw!
nnoremap
set runtimepath^=~/.vim/bundle/ctrlp.vim
colors koehler


시스템 커멘드라인 유틸리티

pacman -S ack
pacman -S ncdu
pacman -S fdupes


GUI 유틸리티

pacman -S transmission-qt
pacman -S filezilla
pacman -S stardict
pacman -S xfce4-weather-plugin
pacman -S gnumeric
pacman -S deadbeef
pacman -S virtualbox
pacman -S virtualbox-guest-modules
pacman -S wine
pacman -S wine_gecko
pacman -S chromium
pacman -S qupzilla
pacman -S thunderbird
pacman -S tomboy
pacman -S festival
yaourt -S marble
yaourt -S gmapcatcher
yaourt -S xnviewmp


화면잠금

yaourt -S xfce-slimlock
이미지 폴더 : /usr/share/slim/themes/default

focuswriter

qt5로 설치시 uim에서 한글 입력이 안되므로 PKGBUILD에서 depends를 qt4로 변경한다.
# Maintainer: Graeme Gott

pkgname=focuswriter
pkgver=1.4.5
pkgrel=1
pkgdesc="A simple fullscreen word processor"
arch=('i686' 'x86_64')
url="http://gottcode.org/${pkgname}/"
license=('GPL3')
#depends=('qt5-base' 'qt5-multimedia' 'enchant' 'libzip')
depends=('qt4' 'enchant' 'libzip')
install=${pkgname}.install
source=(http://gottcode.org/${pkgname}/${pkgname}-${pkgver}-src.tar.bz2)
md5sums=('42b14c9357e5b33d55ddbdb3a97e6af1')
sha256sums=('4fb4d826493b2a8a420762b67c74659574092b641f55442e74a292b6ef5e36f2')

build() {
cd "${srcdir}/${pkgname}-${pkgver}"
#qmake-qt5 PREFIX=/usr
qmake-qt4 PREFIX=/usr
make
}

package() {
cd "${srcdir}/${pkgname}-${pkgver}"
make INSTALL_ROOT="${pkgdir}/" install
}


chrome 설정

https://wiki.archlinux.org/index.php/chromium

chrome 관련 url 보기
chrome://chrome-urls

chrome://flags
Override software rendering list - Enable
Disable accelerated 2D canvas -Enable
Enable WebGL Draft Extensions - Disable
Enable Developer Tools experiments - Enable

실행 옵션
chromium --disk-cache-dir=/scratch/psd --scroll-pixels=320 --disable-accelerated-compositing --cipher-suite-blacklist=0x0001,0x0002,0x0004,0x0005,0x0017,0x0018,0xc002,0xc007,0xc00c,0xc011,0xc016,0xff80,0xff81,0xff82,0xff83

플래쉬 플레이어 설치
yaourt -S chromium-pepper-flash
chrome://plugins 에서 adobe flash player서 기본 flash player disable

프로파일 클리너 설치
sudo yaourt -S profile-cleaner

profile sync daemon 활성화
https://wiki.archlinux.org/index.php/Chromium_tweaks
https://wiki.archlinux.org/index.php/Profile-sync-daemon

yaourt -S profile-sync-daemon

/etc/psd.conf
USERS="dorajistyle"
BROWSERS="chromium firefox qupzilla"
VOLATILE="/scratch"


sudo systemctl enable psd psd-resync


xfce 테마 설정


메뉴 고급 설정

yaourt -S xfce4-whiskermenu-plugin
panel > Items / Window Buttons - Show flat buttons 활성

테마 관련 파일 경로

  • 폰트 : ~/.font
  • 아이콘 : ~/.icons
  • 테마 : ~/.themes

테마 설치

yaourt -S xubuntu-artwork
yaourt -S xfce4-xquisite-icon-theme
yaourt -S xfce4-finalorder-icon-theme
yaourt -S xfce-theme-simplix
yaourt -S zen-gtk-themes


simpliX 테마 설치

  • chrome용 : crx file 을 extension로 드래그
  • 파이어폭스용 :~/.mozilla/firefox/profile.default/chrome/userChrome.css 복사

폰트 렌더링 설정

~/.config/fontconfig/fonts.conf

true
true
hintslight


키보드 단축키

  • super b
    chromium --disk-cache-dir=/scratch/psd --scroll-pixels=320 --disable-accelerated-compositing --cipher-suite-blacklist=0x0001,0x0002,0x0004,0x0005,0x0017,0x0018,0xc002,0xc007,0xc00c,0xc011,0xc016,0xff80,0xff81,0xff82,0xff83
  • super =
    deadbeef
  • super f
    firefox
  • super g
    qupzilla
  • super i
    ~/XnView/xnview.sh
  • super backspace
    leafpad ~/work/article/notes/note.txt
  • control alt del
    slimlock
  • super d
    stardict
  • super n
    tea
  • super e
    thunar
  • super m
    thunderbird
  • super q
    /usr/bin/focuswriter
  • super c
    /usr/bin/qalculate-gtk
  • super t
    /usr/bin/xfce4-taskmanager
  • super y
    /usr/bin/xsensors
  • super p
    xfce4-display-settings --minimal
  • ctrl print (region)
    xfce4-screenshooter
  • alt print (window)
    xfce4-screenshooter -w
  • print
    xfce4-screenshooter -r
  • super s
    xfce4-terminal
  • super v
    gvim
  • ctrl alt x
    xfce4-session-logout

HDMI와 노트북 모니터 동시에 켜기

루트 유저로 다음 파일을 추가한다.
/usr/local/share/hdmi-plugged-startup
#!/bin/bash

export XAUTHORITY=/home/$USER/.Xauthority
export DISPLAY=:0

/usr/bin/xrandr -display :0 --output eDP1 --auto --output HDMI1 --auto --above eDP1


이 파일을 실행 가능하게 만든다.
chmod +x /usr/local/share/hdmi-plugged-startup
And add the following udev rule:
다음 udev rule을 추가한다.
echo 'ACTION=="change", SUBSYSTEM=="drm", RUN+="/usr/local/share/hdmi-plugged-startup"' >> /etc/udev/rules.d/10-local.rules


문제 해결


재부팅을 하면 화면이 제대로 동작하지 않고, /usr/local/share/hdmi-plugged-startup를 실행하면 아래의 오류가 날 때.

No Protocol specified
Error cannot open display :0.0
echo $HOSTNAME 으로 호스트 이름을 확인한다.

/etc/NetworkManager/NetworkManager.conf 파일을 열어 다음을 추가한다.
[keyfile]
hostname=<your_hostname>

xhost 권한 추가.
xhost +SI:localuser:<user>

X server가 실행되지 않을 때

mhwd 로 다른 그래픽 드라이버를 제거한 후, 사양에 맞는 드라이버를 재설치

mhwd -r pci video-nvidia
mhwd -r pci video-intel
mhwd -r pci video-hybrid-intel-nvidia-bumblebee
mhwd -i -f pci video-hybrid-intel-nouveau-bumblebee

https://forum.manjaro.org/index.php?topic=10120.0
https://forum.manjaro.org/index.php?topic=76.0

Asus ux31a 관련

https://wiki.archlinux.org/index.php/ASUS_Zenbook_Prime_UX31A
https://wiki.debian.org/InstallingDebianOn/Asus/UX31a
https://help.ubuntu.com/community/AsusZenbookPrime#Optimizing_for_SSD
http://community.linuxmint.com/tutorial/view/1366
https://wiki.archlinux.org/index.php/Solid_State_Drives#Advantages_over_HDDs
https://wiki.archlinux.org/index.php/ASUS_Zenbook_Prime_UX31A#HDMI_plugged_at_boot



by


Tags : , , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

귀찮은 일은 다 맡겨라. Grunt Javascript task runner.


특정 디렉토리 안에서 파일이 수정되면 컴파일을 해야 하는 상황이 생겼다.
글자 하나 바꿀 때마다 일일이 그런 수고를 하려니 여간 귀찮은 일이 아니다.
이런 때는 보통 bash 쉘 스크립트를 써 왔는데, os관계없이 어디서나 작동하고, 간편한 녀석을 찾다가 grunt(http://gruntjs.com)를 만나게 되었다. grunt는 프론트엔드 계통에선 꽤 이름을 날리는 녀석으로, 초반 웹 환경 구축을 도와주는 Yeoman(http://yeoman.io)의 한 부분이기도 하다. 요즘엔 grunt와 비슷한 gulp(http://gulpjs.com)이 성능 면에서 우수해서 인기가 좋은데, 여러 작업을 연달아서 할 때 pipe를 이용해서 I/O에 들어가는 시간을 줄이기 때문이란다. 그러나 나는 지금 연속적인 작업에 쓸 것도 아니고, grunt에서도 조만간(?) pipe를 지원할 예정이라고 하니, 커뮤니티가 활성화된 grunt를 쓰기로 했다.

grunt 설치

npm i grunt-cli -g

grunt를 실행할 해당 폴더에서 로컬 모듈 인스톨( 예 : static 폴더에서 실행시 static 폴더에 가서 인스톨)

npm install can-compile --save-dev
npm install grunt-shell --save-dev
npm install grunt-contrib-watch --save-dev
npm install time-grunt --save-dev


grunt 설정파일 예제 - Gruntfile.js

module.exports = function (grunt) {
    var static_path = '../static';

    // Project configuration.
    require('time-grunt')(grunt);
    grunt.initConfig({
//        pkg: grunt.file.readJSON('./package.json'),

    shell: {
      scsscompile:{ // scss컴파일은 외부 파이썬 스크립트를 이용해서 한다. 그래서 grunt-shell이 필요하다.
        command: 'python2 ../css.py '+static_path,
        options: {
            stdout: true
        }
      }
    },
    cancompile: { // mustache파일을 하나의 자바스크립트 파일로 합쳐주는 모듈
        dist: {
            src: [static_path+'/views/**/*.mustache'],
            out: static_path+'/js/views.build.js',
            wrapper: 'define(["can/view/mustache"], function(can) { {{{content}}} });'
        }
    },
    watch: { // grunt watch를 실행하면 해당되는 파일 변경사항이 생길 때 마다 스크립트를 자동으로 실행 한다.
      run_mustache: {
        files: [static_path+'/views/**/*.mustache'],
        tasks: ['cancompile']
      },
      run_scss: {
            files: [static_path+'/scss/**/*.scss'],
            tasks: ['shell:scsscompile']
      },
        options: { nospawn: true, livereload: true } // watch 성능이 향상된다.
    }
  });

//   grunt.registerTask('default', ['watch']); 로 설정하면, 파라미터 없이 grunt를 실행할 때 watch를 실행한다.
  grunt.registerTask('watch', ['watch']);
  grunt.registerTask('mustache', ['cancompile']);
  grunt.registerTask('scss', ['shell:scsscompile']);
  grunt.registerTask('static', ['cancompile','shell:scsscompile']);

  grunt.loadNpmTasks('can-compile');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-contrib-watch');
};
이 간단한 설정 파일 하나로, 쓸만한 watcher가 만들어졌다. :D
앞으로도 귀찮은 작업을 떠넘길 때 종종 이용해야겠다.

문제 해결


npm이 sudo 권한 없이 설치되지 않을 때

http://stackoverflow.com/questions/16151018/npm-throws-error-without-sudo
sudo chown -R `whoami` ~/.npm
sudo chown -R `whoami` ~/node_modules
sudo chown -R `whoami` /usr/lib/node_modules


Grunt - Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral. 에러가 발생할 때.

http://stackoverflow.com/questions/22285942/grunt-throw-recursive-process-nexttick-detected
grunt.registerTask('sass',['sass']); // 이런식으로 작업 이름과 등록 이름이 같을 때 문제가 발생한다.
grunt.registerTask('styles',['sass']); // 이런식으로 이름을 바꿔준다.

유용한 링크

http://gruntjs.com/
http://gulpjs.com
http://jaysoo.ca/2014/01/27/gruntjs-vs-gulpjs/
http://yeoman.io/blog/performance-optimization.html



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

애증의 사바용. Sabayon Linux.

주 OS를 리눅스로 바꾼 뒤로 Arch리눅스 기반의 Manjaro를 쭉 써왔다.
그러다 반년 전 랩탑을 바꾸면서 새로운 리눅스 배포판을 사용해 보기로 했는데,
바로 Gentoo기반의 Sabayon 리눅스다.
젠투의 장점이라면, 내가 원하지 않는 쓰잘데 없는 패키지를 설치하지 않고 딱 원하는 것만 설치할 수 있다는 것이다.
그래서 때때로 아주 기본적인 기본을 동작시키는데도 어마어마한 노력이 들어가기도 한다.
오 년 전쯤 주 OS를 리눅스로 바꿔보겠다며 일주일 동안 젠투와 씨름하다가 그래픽카드 드라이버를 못 잡고 좌절했던 기억이 떠오른다.
‘그래. 그땐 그랬지. 하지만 시대는 많이 변했으니까.’
설치하기도 편리한 젠투 기반의 배포판 사바용.
아무런 문제도 없이 설치되었고, 쓰는데도 무리가 없었다.
그런데 어느 날 갑자기 알 수 없는 오류를 내며 부팅이 되지 않았다.
빌어먹을.
‘이 기회에 다른 리눅스로 바꿔 타?’
다른 여러 배포판을 설치해 보려고 낑낑거렸지만, 대부분 리눅스 배포판에서 UEFI를 제대로 지원하지 않았다.
빌어먹을.
울며 겨자 먹기로 다시 애증의 Sabayon 리눅스를 설치했다.
이걸 쓰면서 여러 문제와 맞딱뜨린다.
버츄얼박스를 켜면 컴퓨터가 다운되질 않나….
그래도 다른 걸 새로 깔 엄두가 나지 않아서 계속 썼는데,
이번에 아주 큰 문제가 발생했다.
WIFI를 못잡는거다.
랩톱인데 무선 인터넷을 못 잡으면 끝이다.
WIFI를 잡아보려고 여러 글을 읽어보고 수많은 시도를 해봤지만, WIFI는 결코 동작하지 않았다.
신호를 못 잡는 건 아니고, 신호가 잡혀서 연결을 시도하면, 연결되지 않는 문제인데 다른 기기에선 잘 잡히는 무선 인터넷이 유독 랩톱에서만 안 잡힌다.
망할.
일주일도 넘게 와이파이랑 씨름하다가 느꼈다.
‘내가 왜 와이파이 하나 잡는데 일주일을 보내야 해?’
누군가 젠투를 사용한다면 리눅스 전문가이거나, 사디스트가 분명하다.
설령 지금은 그 둘 중 하나가 아니더라도 계속 쓰면 그렇게 될 수밖에 없겠다.
어쨌거나 나는 그 둘 중 하나가 되기 전에 젠투 기반의 Sabayon을 떠나기로 마음먹었다.
무선 인터넷 잡자고 일주일을 더 보내긴 싫으니까. 그렇다고 잡힌다는 보장도 없고.
안녕! 애증의 Sabayon.

아래는 그동안 Sabayon을 사용하며 적은 노트이다.

Sabayon 버전 정보

cat /etc/sabayon-release

커널 정보 보기

eselect kernel list

엔트로피 업데이트

equo update
equo upgrade
equo conf update

grub 설정

/etc/default/sabayon-grub

auto login

lightdm
/etc/lightdm/lightdm.conf
[SeatDefaults]
autologin-user = username
utologin-user-timeout =0

slim
/etc/conf.d/xdm
DISPLAYMANAGER="slim"
rc-update add xdm default
/etc/slim.conf
defaultuser yourusernamehere
auto_login yes

session 삭제

$HOME/.cache/sessions

VirtualBox 설치

http://wiki.sabayon.org/index.php?title=HOWTO:UsingVirtualbox
vboxdrv 오류시
modprobe -r vboxdrv
modprobe vboxdrv

Midori

http://wiki.xfce.org/midori/faq
~/.cache
export XDGCACHEHOME=/dev/shm

한글 입력

http://wiki.gentoo-kr.org/index.php?title=GentooKoreanEnv
폰트 설치해 준다.
Sabayon 10.8 mate버젼에서는 한글이 잘 안써져서 입력기를 따로 설치해야 했지만,
Sabayon 10.8 xfce버젼에서 ibus로 한글 잘 써진다.
Session and startup > Application Autostart에 ibus-daemon을 추가한다.
ibus-daemon -drx

영문키보드에서 한영키 사용

Setting -> Keyboard -> Layout
Keyboard model : Generic 105-key (Intl) PC (Generic중 아무거나 해도 되는듯)
Leyboard Layout : Korean / Korean (101/104 key compatible)
IBus Preferences -> Advanced -> Keyboard Layout에서 Use system keyboard layout에 체크한다.

CPU점유율 100%

테마 선택에 따라 CPU점유율에 차이를 보일 수 있다.
Equinox 테마를 사용했더니 자꾸 CPU 점유율 100이 되고 컴퓨터가 먹통이 된다.

OpelGL setting

sudo eselect opengl list
sudo eselect opengl set 1


xnview

xnview 구동을 위해선 libpng12를 설치해야 한다.

개발

java 설정

OpenJDK를 사용시 Intellij를 쓸 때 성능 저하가 일어나므로 Oracle Jdk Bin을 설치한다.
Oracle Jdk를 기본 vm으로 설정한다.
java-config --list-available-vms
java-config --set-system-vm=oracle-jdk-bin
env-update

Maria db 설치

  • mysql 삭제
  • maria db 설치
  • sudo mysqld_safe 실행
  • Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist 에러 발생
  • sudo /usr/share/mysql/scripts/mysqlinstalldb --basedir=/usr
  • sudo mysqld
  • /usr/bin/mysqlsecureinstallation
  • 완료
http://forums.gentoo.org/viewtopic-p-7333862.html
rc-update add mysql
rc-update del mysql


/etc/systemd/system/mysqld.service:
[Unit]
Description=MySQL Server
After=network.target


[Service]
ExecStart=/usr/bin/mysqld_safe --defaults-file=/etc/mysql/my.cnf --datadir=/var/lib/mysql --socket=/var/run/mysqld/mysqld.sock
User=mysql
Group=mysql
WorkingDirectory=/usr

[Install]
WantedBy=multi-user.target

sudo systemctl status mysqld.service
http://superuser.com/questions/384365/systemctl-enable-differs-from-systemctl-start-how

Sabayon 사용시 유용한 링크

http://wiki.sabayon.org/index.php?title=Howtooptimizeandaccelerateyoursystem
https://wiki.sabayon.org/index.php?title=HOWTO:UpgradekernelusingEntropy
https://wiki.sabayon.org/?title=HOWTO:UpgradekernelusingEntropy
https://wiki.sabayon.org/index.php?title=En:FAQ#HowDoIenableAutologin.3F
http://wiki.gentoo.org/wiki/Localization/HOWTO
http://www.gentoo.org/proj/en/perl/g-cpan.xml



by


Tags : , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

아마존 클라우드 AWS. 효율적인 설계를 위한 Architecting on AWS.


퍼블릭 클라우드 하면 Amazon, Google, Microsoft 이 세 회사가 떠오른다.
이 세 곳 중에 어느 클라우드가 좋을까 여러 글을 찾아보았다.
모두 장단점이 있지만, 결국 개발자 입장에서 제일 편한 AWS를 쓰기로 마음을 먹었다.
Microsoft의 azure는 말로는 다 쉽게 된다는데,
막상 실제로 하려면 참조 자료도 별로 없고 원하는 데로 되질 않는다.
구글 클라우드 플랫폼은 꽤 안정적으로 보이긴 하지만,
이미 너무 많은 구글 제품을 쓰고 있는 나는 좀 다른 걸 써 보고 싶었다.
사실 더 큰 이유는 구글 클라우드를 쓰기로 마음먹고 개발한 것이 아니므로
이대로 구글에 배포하면 구글에서 제공하는 좋은 자원을 제대로 활용하지 못하기 때문이다.
그래서 결정한 AWS.
좀 써보니 라이브러리도 잘 되어있고 마음에 든다.
그러나 글로만 배운 것은 한계가 있는 법.
춤을 직접 춰봐야 늘지 글로 배워봤자 얼마나 배우겠는가?
기술도 마찬가지로 직접 써봐야 익숙해지고 는다.
그래서 실습과 교육이 적절히 이루어진 Architecting on AWS교육을 듣게 되었다.
교육이 재미있고 지루할 틈 없이 지나가서 아주 만족스럽다.
분기별 한 번씩은 열릴 예정이라고 하니,
AWS에 관심을 가진 사람은 한번 들어볼 만하다.

Architecting on AWS 메모와 팁


보안

설계

  • private subnet에서 밖으로 나갈 땐 Network address translation (NAT) 서버를 이용한다.
  • 서버에 바로 접속을 허용하지 말고, Bastion 서버를 통과해서만 접속이 가능하도록 한다.
  • EIP를 이용하는 것 보다 ELB를 이용하는편이 보안에 좋다.

권한

  • 마스터 유저는 사용하지 말고, IAM(Identity and Access Management)를 이용해 각각의 권한을 지닌 사용자를 만들어 쓴다.
  • 항상 권한을 가질 필요가 없다면, STS(Security Token Service)f를 이용해 사용자가 필요한 임시 권한을 주었다가 회수한다.
  • 유저는 Role을 가지거나 User Group에 속해서 권한을 가지는 경우가 있는데, STS를 통해 Role을 지닌 유저 키를 받아오면 보안에 더 좋다.

좋은 클라우드 설계를 위한 안티패턴과 패턴

안티패턴/ 패턴

  • 수동 프로세스 / 자동 프로세스
  • 밀결합(Thightly-coupled) / 소결합(Loosely-coupled)
  • 세션 사용(Stateful) / 세션 미사용 (Stateless)
  • 수직적 확장 / 수평적 확장

자동 구성 도구(Bootstrapping)

  • 스크립트 (Bash, 파워쉘)
  • 구성관리 도구(Chef, Puppet)
  • Amazon OpsWorks
  • http://169.254.169.254/latest/meta-data/

AWS 제품 소개 / 팁

네트워크

Router 53

서버 부하가 많이 걸리면 DNS(Router 53)에 Round-robin 설정 후,
동일 도메인 (예:dorajistyle.pe.kr)에 서브도메인(Record Type A)으로 각 서버의 ip를 설정한다.
www.dorajistyle.pe.kr은 CNAME타입으로 dorajistyle.pe.kr에 연결한다.
그러나 이 방법은 서버를 추가할 때마다 매번 설정을 변경해야 하는 불편함이 있다.
ELB를 사용하면 이런 불편함을 줄일 수 있다.
Router 53에는 Alias type이 있어서 value에 도메인을 넣으면 alias된다.
elb주소를 alias하려면 dorajistyle.pe.kr의 alias로 ELB주소를 붙인다.

ELB

ELB 참조 시, IP 어드레스를 절대로 사용하지 말고 A레코드를 항상 사용한다.

CloudFront

약정 할인 되고, 유일하게 네고가 가능한 서비스다.
월 10테라 이상이면 CloudFront가 S3보다 저렴하다.
정적(static) 컨텐츠 뿐 아니라 동적(dynamic) 컨텐츠도 캐쉬 가능하다.
그러나 동적 컨텐츠를 캐쉬하게 되면 비용적인 부담이 생길 수 있다.

스토리지

Amazon EBS

내구성이 필요하고 공유 가능한 스토리지를 원한다면 사용한다.

Amazon RDS

데이터베이스

DynamoDB

NoSQL 데이터베이스

S3

Eventually Consistent기 때문에 수정 결과가 바로 반영되지 않을 수 있다.
RRS(Reduced Redundancy Storage, RRS)
표준 스토리지보다 중복 수준을 낮추어 비용을 절감한다. 내구성 99.99%
S3는 Request당 과금하기 때문에, S3에 올리고, 그것을 가공해서 다시 S3에 올릴때도 비용이 발생한다.
한번의 Request에 여러 개의 파일을 묶어서 업로드가 가능하다.

배치

SNS

Http, Email, SMS, 모바일 푸쉬 등 여러 대상에 Push한다.

SQS

단순 큐.
큐에 있는 것을 처리하는 EC2서버는 ELB에 물려 있을 필요가 없다.
EC2서버가 항상 SQS 큐를 바라보기 때문에 큐 자체가 ELB역할을 하기 때문이다.

SWF

여러가지 작업을 실행할 때 여러개의 큐를 생성할 필요 없는 여러 작업의 워크플로우(BUS)
순차적으로 이루어져야 하는 경우에 유리하다.

CloudFormation

현재 구성을 JSON형식으로 정의한다.
다른 환경에서 같은 환경을 구축하려고 할 때 유용하다.

CloudInit

EC2 인스턴스를 생성할 때 userdata에 스크립트를 넣으면 첫번째 부팅시 사용자 데이터를 스크립트로 인식하여 실행한다.
#!(리눅스)
<script> (윈도우)

AMI

Ami에서 aws cli로 s3에서 원하는 부분 복사가 가능하다.

관리

CloudWatch

Metric 측정 도구이다.
5분 단위로 측정은 무료, 1분 단위로 측정하면 인스턴스당 $3.5
커스텀 측정치는 측정치당 월 $0.50

CloudWatch

지정된 범위가 침해되면, 경보를 발생하여 지정된 액션을 실행한다.
* SMS 통지
* 이메일 전송
* AutoScaling
* 인스턴스 정지
5분 주기면 무료이고, 1분 주기로 체크하면 과금이 된다.

Auto Scaling

보일러 온도 조절기를 생각하면 편하다.

desired capacity : 초기에 띄울 인스턴스 갯수
min : 최소 인스턴스 갯수
max : 최대 인스턴스 갯수
AZ-a,b : 어느 존에 인스턴스를 띄을 것인가? (desired capacity/AZ 해서 각 AZ에 인스턴스를 띄워준다.)
서버 갯수가 고정인 경우라도 Auto Scaling을 쓰면 안정성이 향상된다.
(예 : desired capacity = 1 max = 1 AZ-a,b)
어플리케이션 서버에 문제가 생기면 자동으로 새로 띄워준다.
AZ에 문제 발생시 문제가 없는 AZ에 인스턴스를 띄워준다.
사람이 직접 실행하거나, CloudWatch알람을 걸어서 자동으로 실행할 수 있다.

예)
인스턴스가 가동하기까지 준비시간이 필요하므로, 스케일 아웃은 미리 하고, 스케일 인은 보수적으로 한다.
인스턴스가 생성되면 기본 한시간 비용은 나오기 때문에, 스케일 아웃과 스케일 인이 너무 빈번하게 일어나면 좋지 않다.
트리거: CPULoad
측정치 (M) : 평균 CPU사용량
5분간 M > 80% 이면 스케일 아웃
20분간 M < 40% 이면 스케일 인

오토 스케일링 시나리오

Service - EC2 선택
ELB 생성 TCP프로토콜 + 80 포트, Health Check Interval은 적절한 값(예: 0.1)으로 설정한다.
Launch Configuration 생성
Security Group에 HTPP Rule을 추가한다.
Auto Scailing Group 생성
서브넷은 1개 이상 추가한다.
설정에서 Receive traffic from Elastic Load Balancer(s)에서 로드 발란서를 선택한다.
Keep this group at its initial size에 체크하고 생성한다.
인스턴스에 우클릭해서 오토 스케일링으로 생성된 인스턴스에 태그 부여.
설정 버튼에서 aws:autoscaling:groupName을 선택한다.
SNS토픽을 생성 한다.
E-mail Subscription을 생성한다.
Auto Scaling 연동 설정한다.
CloudWatch로 CPU Alert 생성한다.
Create Alarm > AutoScaling 검색 > CPUUtilization
Define Alarm Threshold 를 잘 설정한다.
(예) 부하가 50이상일 때 >= 50)
Auto Scaling Policy를 생성 생성한다.
해당 알림에 따라 실행할 동작 지정한다.

비용

네트웍 비용은 나가는 것을 기준으로 한다.
On-demand instances 소매가
Reserved instances 약정할인 (선납금을 조금 내고 조금 할인 받거나, 많이 내고 많이 할인 받는다.
Spot instances 남는 인스턴스를 경매 방식으로 구입해서 사용한다. (가격변동이 있다.) 경매에 지면 자동으로 꺼진다.
일반적인 백그라운드 프로세싱에 사용한다.
하나의 ELB에 여러개의 ASG(Autoscaling Group)을 붙일 수 있다. 예를 들면 하나는 온디멘드, 다른 하나는 스팟 인스턴스 그룹으로 만들어 두면 하이브리드 구성이 가능하다.

링크

아키텍팅

http://aws.amazon.com/ko/architecture/
http://prezi.com/cxpwi_og7lht/aws-regions-and-availability-zones/
http://translate.google.com/translate?hl=ko&sl=ja&tl=ko&u=http%3A%2F%2Faws.clouddesignpattern.org%2Findex.php%2F%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8

보안

http://blogs.aws.amazon.com/security

AWS Elastic Beanstalk

http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts.platforms.html
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/createdeployPythoncustomcontainer.html
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers.html

최적의 비용 계산기(기술지원 신청하면 사용 가능)

http://aws.amazon.com/support/trustedadvisor



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

똑똑한 웹사이트 성능 테스트. sitespeed.io


웹 사이트 성능을 테스트해주는 곳은 많다.
온라인에서 사이트 성능을 측정해주는 핑돔(http://tools.pingdom.com/fpt/) 같은 서비스도 있고,
크롬을 주로 쓰는 개발자라면 크롬 개발자 도구에 Pagespeed(https://developers.google.com/speed/pagespeed/)을 깔아 쓰는 방법도 있다.

sitespeed.io(http://www.sitespeed.io/)는 우연히 찾아낸 웹사이트 성능 테스트 도구인데,
이걸 보고 웃음이 절로 나왔다.
스머프처럼 랄랄라랄랄라 노래를 흥얼거리고 깡총 거리면서 걷게 되었다.

나를 기분 좋게 한 sitespeed.io의 특징

  • 여러 페이지를 한 번에 테스트할 수 있다.
  • 다양한 뷰포트를 지원한다.
  • 유저 에이전트를 직접 지정해도 된다.
  • 결과를 html 페이지로 깔끔하게 보여준다.
  • 덤으로 페이지별 스크린 샷도 찍어 준다.
'아! 정말 아름다운 테스트 도구다!'
라는 감탄이 절로 나왔다.
그러나 기대가 크면 좌절도 큰 법.
내가 원하는 용도로 쓰려면 기능이 부족했다.

아쉬운 점 두 가지.

  • RESTful 사이트를 지원하지 않는다.
  • 테스트에 쿠키 정보를 넘기지 못한다.
이 두 가지가 되지 않는다면, 이 도구는 내게 아무 쓸모가 없다.
보기만 좋지, 제대로 된 능력을 발휘하지 못하는 것이다.
마치 사막에 버려진 고래처럼...

다행인 점은 sitespeed.io(http://www.sitespeed.io/)가 오픈소스라는 점이다.
그래서 나는 이 녀석과 불금을 보내고, 주말까지 함께했다.
덕분에 RESTful테스트는 해결되었고, 쿠키부분은 몇 부분 더 손 봐야 하지만,
곧 두 가지를 보완한 정식 버전이 나올 예정이다.

혹시 정식 버전이 나오기 전에 써보고 싶다면 아래 두 저장소를 clone 받아 사용하면 된다.
* https://github.com/dorajistyle/yslow
* https://github.com/dorajistyle/sitespeed.io

yslow를 컴파일해서 sitespeed.io/dependencies/yslow-3.1.5-sitespeed.js로 붙여넣으면 테스트가 가능하다.

yslow 컴파일 방법

sudo make phantomjs

curl 쿠키 저장 (여기서 나오는 쿠키 정보를 텍스트로 넣어주면 된다.)

curl -c sitespeed.io/cookie -X POST -H "Content-Type:application/x-www-form-urlencoded;charset=UTF-8" -d 'loginEmail=admin@dorajistyle.pe.kr&loginPassword=password' http://dorajistyle.url/authentications

yslow 쿠키 테스트(yslow 폴더에서 실행)

phantomjs ./build/phantomjs/yslow.js --info basic --format plain 'http://dorajistyle.url/admin' -C '{"name":"session","value":"sessionvaluestring","domain":"localhost"}'

screenshot 쿠키 테스트 (sitespeed-result 폴더에 저장됨)

phantomjs --ignore-ssl-errors=yes sitespeed.io/dependencies/screenshot.js 'http://localhost/#!test/page' sitespeed.io/sitespeed-result/screenshots/screenshot.png 1280 800 'Mozilla/5.0 (Macintosh; Intel Mac OS X 1084) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36' true '{"name":"session","value":"sessionvaluestring","domain":"localhost"}'

로그를 포함한 sitespeed.io 쿠키 테스트 (sitespeed.io 폴더에서 실행)

sh -x ./bin/sitespeed.io -f batchlist -k true -p 10 -C '{"name":"session","value":"sessionvalue_string","domain":"localhost"}'



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

joinedload를 사용한 SQLAlchemy 쿼리 최적화


SQLAlchemy는 파이썬(Python)용 Object Relational Mapper다.
ORM(Object Relational Mapper)은 객체(Object)와 관계형 데이터베이스(RDB - Relational Database)의 데이터 타입을 연결해 주는데,
이게 나오기 전엔 개발을 어떻게 했었나 싶을 정도로 아주 편리하다.

사용법도 간단해서 짧은 코드로 쿼리를 날리면 모델 하나를 딱 불러온다.
Model.get(model_id)
정말 좋다.
아무런 문제가 없었다.
적어도 외부 DB를 사용해 시험해 보기 전엔 그랬다.
외부 DB는 요청을 보내고 받는 시간이 길다.
헌데 SQLALCHEMY에서 자동으로 만들어 주는 쿼리를 쓰면, 너무 많은 요청을 보내게 된다.
그렇다면 성능을 향상하기 위해선?
요청 수를 줄이면 된다.

예제 모델-'SQLAlchemy Query Optimization. 쿼리 최적화'

예제의 product테이블은 여러 테이블과 연결되어 있는데,
쿼리를 날려 product와 관련된 테이블의 정보를 모두 불러와야 한다.
Sqlalchemy의 기본 쿼리 설정은 select로 연관된 table을 독립된 SELECT쿼리로 호출하지만,
응답시간이 느린 외부 DB를 쓴다면, 이를 join해서 쿼리 개수를 줄이면 된다.

sqlalchemy에서 join은 어떻게 하는가?

모델을 생성할 때 lazy='joined'를 써서 관련 테이블을 부를 때 join하는 방법과,
joinedload를 이용한 join 방법이 있다.
모델 생성 시 lazy를 사용해 join한 경우, 모델 호출 시마다 join이 되므로,
예제에선 필요한 상황에만 쿼리를 join하는, joinedload를 사용했다.

joinedload 간략 사용 방법

Model.query.options(db.joinedload(Model.relatedModel).all()

SQLAlchemy 쿼리 최적화 방법

  • 1..1 관계는 innerjoin한다.
    db.joinedload(Seller, innerjoin=True)
  • 1..n 관계는 innerjoin하지 않는다.
    db.joinedload(Tags)
  • 1..n 관계에서 관계가 깊다면, subqueryload를 써서 관련 테이블을 불러오고,
    그에 대해 joinedload를 해준다.
    db.subqueryload(Colors),
    db.joinedload(Colors, Inventory)
SQLAlchemy Query Optimization. 쿼리 최적화

위 방법을 써서 Call 개수를 25% 줄였다.
보통 Call이 29~30개가 나오다가, 22로 줄었으니, 약 7.5개 준 것이다.
Call당 시간이 얼마나 걸리냐에 따라 시간 단축이 가능한데,
테스트 환경에서 0.08초 정도 걸렸으므로 약 0.6초(0.08 * 7.5) 의 시간을 단축했다.
이건 데이터베이스의 응답 지연이 얼마나 되느냐에 따라 더 큰 차이를 보인다.
물론 로컬 db에서는 percall시간이 아주 짧으므로(테스트 환경에선 0.001초) 이런 최적화 차이를 체감하지 못한다.

참조

http://docs.sqlalchemy.org/en/rel09/orm/relationships.html
http://docs.sqlalchemy.org/en/rel09/orm/loading.html
http://stackoverflow.com/questions/6935809/how-to-use-joinedload-contains-eager-for-query-enabled-relationships-lazy-dyna
http://invenio-software.org/wiki/Tools/SQLAlchemy/Performance



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

서버에 부하가 얼마나 걸리나? Jmeter Http 부하(Load) 테스트.



여러 테스트 도구 중 Apache Jmeter를 선택한 이유.

  • 오픈소스.
  • 간편함.
  • 결과를 직관적으로 보여줌.
  • 사용자가 많음.
  • 문서 잘 된 편임.

Jmeter Http 부하 테스트 작성 순서

  1. Jmeter를 내려받는다. (http://jmeter.apache.org/download_jmeter.cgi)
  2. 압축을 풀고 Jmeter를 실행한다.
  3. Test Plan에 자식 노드 Thread Group를 추가한다.
  4. Therad Grup에서 Properties에 원하는 값을 넣어준다.
    Number of Thread는 테스트할 사용자의 수이고,
    Ramp-Up Period는 테스트를 몇 초에 걸쳐서 실행할 것인지 기간을 말한다.
    만약 Number of Thread가 10이고, Ramp-Up Period가 100이라면 각각의 Thread가 10초마다(100/10) 시작된다.
    하나의 Thread가 실행되고 10초의 여유 시간을 가지고 다음 Thread를 실행하는 것이다.
    Loop count에는 이 Thread를 몇 번 반복할지 적어준다.
  5. *만약 요청(Request)에 헤더 값을 설정해 줘야 한다면, Thread Group에 자식노드 HTTP Header Manager를 추가한다.
    Name과 Value값을 넣어주면 설정이 완료된다.
    예를 들자면 Name란에 Content-Type, Value란에 application/json을 적어주면 Content-Type이 application/json으로 설정된다.
  6. Thread Group에 자식 노드 HTTP Request를 추가한다.
  7. HTTP Request의 Web Server 란에 서버 이름(혹은 IP)와 포트 번호를 설정 한다.
  8. HTTP Request의 Path에 요청을 보낼 경로를 적어준다. (예: /about/company.html)
  9. HTTP Request의 Method를 Get으로 설정한다.
  10. HTTP Request에 자식 노드 Listener를 추가한다.
    여러 종류의 Listener가 있는데, View Results Tree는 각각의 요청에 대한 응답 결과를 보여주고,
    Summary Report는 종합적인 테스트 결과를 테이블로 보여준다.
    그리고 Spline Visualizer는 종합 결과를 그래프로 보여준다.
  11. *만약 여러 Thread Group에 대한 종합 결과를 보고 싶다면, Test Plan에 자식 노드로 Listener를 추가하면 된다.

아래는 예시를 위해 Jmeter로 테스트한 Spline Visualizer 결과값이다.

Flask 개발용 서버-'Jmeter로 Http 부하 테스트하기'
Flask 개발용(dev) 서버.

twisted-'Jmeter로 Http 부하 테스트하기'
twisted

twisted + Nginx -'Jmeter로 Http 부하 테스트하기'
twisted + Nginx

gunicorn + Nginx -'Jmeter로 Http 부하 테스트하기'
gunicorn + Nginx

각 테스트의 Summary Report를 정리한 표.-'Jmeter로 Http 부하 테스트하기'
각 테스트의 Summary Report를 정리한 표.

배포하기 전에 어떤 조합 성능이 좋을지 궁금하다면,
Jmeter를 이용해 각각 환경을 간단히 시험해 보면 좋다.

참고 자료



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.