alt+tab 누르기 피곤할 때. X11에서 xdotool을 이용한 빠른 창 전환.

창을 여러 개 띄워놓은 상태에서 원하는 창을 alt+tab으로 찾아가기란 여간 불편한 일이 아니다.
셸 두 개, 브라우저 두 개, 노트 하나, 폴더 탐색기, 에디터 하나.... 이런 식으로 창을 많이 띄울 수록 더 귀찮다.
그중에 가장 귀찮은 일은 듀얼모니터를 사용하며 브라우저를를 모니터 마다 하나씩 띄워놓고, 하나는 개발용. 하나는 검색용으로 쓸 때다.
코딩하다가 빠르게 검색용 브라우저를 키고 싶은데 alt+tab을 열심히 눌러 찾아간 브라우저가 개발용이라면? 다시 여러 번 alt+tab을 눌러야 한다.
귀찮다.
에디터와 검색용 브라우저 둘 사이만 은밀하게 오가는 단축키가 있으면 좋겠다.
그래서 만나게 된 xdotool(http://www.semicomplete.com/projects/xdotool/).
창을 열고 키 입력까지 자동으로 날릴 수도 있을 정도로 X11윈도우를 주무르는 자동화 도구다.
xdotool은 다양한 리눅스 배포판을 지원하고 맥에서도 맥포트(http://www.macports.org/)로 설치된다.
자 그럼 xdotool을 이용한 창 전환 방법을 알아보자.

빠른 창 전환 단축키 등록 순서.

  1. 셸 스크립트를 원하는 곳에 넣어 둔다.
  2. 스크립트 파일에 실행권한(755)을 준다.
  3. 단축키 등록란으로 가서 셸 스크립트를 넣고 원하는 단축키를 넣는다.
    (예: 에디터/웹 브라우저 창 전환은 super+1, 개발자 도구 창 보여주기는 super+2)

창 전환용 셸 스크립트


창 전환 셸 스크립트 소스 링크

#!/bin/bash
# X11 quick window activation between web browser and editor.
# This script requires (http://www.semicomplete.com/projects/xdotool/)
# Toggling between web browser and editor, just put 'toggle_window.sh' into your keyboard shortcut.
# When you want to show up Development tool window, put 'toggle_window.sh devtool' into your keyboard shortcut.
# Improvements are welcome
# Public Domain, JoongSeob Vito Kim, 2015

activate_name=$(xdotool getactivewindow)
browser_name=""
# This example use 'atom' editor but you can use any kind of editor(vim,emacs,sublimetext...), IDE(Eclipse,Jetbrain...) or others.
editor_name=$(xdotool search --name 'atom' | tail -1)
editor_name_length=${#editor_name}
if (( $editor_name_length == 0 )); then
editor_name=$(xdotool search --name 'focuswriter' | tail -1)
fi
# This example use 'chrome' browser but you can use any kind of browser.
dev_tool_name=$(xdotool search --name 'Developer Tools' | tail -1)
browser_names=$(xdotool search --name 'chrome')
if [[ $1 == "devtool" ]]
then
xdotool windowactivate $dev_tool_name
else
while read line; do
# Please check your browser window's geometry and replace 1920x1080 to yours.
browser_name_temp=$(xdotool getwindowgeometry $line | grep 1920x1080)
length=${#browser_name_temp}
if (( $length > 0 )); then
browser_name=$line
fi
done <<<"$browser_names" echo "browser name = $browser_name" if test "$activate_name" == "$browser_name"; then echo $editor_name xdotool windowactivate $editor_name else echo $browser_name xdotool windowactivate $browser_name fi fi

이 스크립트는 2가지 기능을 한다.
첫째 웹 브라우저와 에디터 사이를 빠르게 오가며 보여주는 역할이고 둘째, 크롬 개발자 도구를 보여주는 역할이다.
이 스크립트를 자신의 환경에 맞게 쓰려면 크게 4부분을 고치면 되겠다.

  1. editor_name에 atom이라고 쓰인 부분을 주로 쓰는 에디터로 바꾼다.
  2. editor_name에 focuswriter라고 쓰인 부분을 보조 에디터로 바꾼다.
  3. browser_names에서 chrome으로 쓰인 부분을 주로 쓰는 웹 브라우저로 바꾼다.
  4. browser_name_temp에서 1920x1080부분을 자신의 브라우저에 맞게 변경한다.
    (xdotool getwindowgeometry <window-id> 를 쓰면 자신의 브라우저 창 설정이 보인다.)

이 스크립트는 alt+tab을 누를 횟수를 많이 줄여준다.:D



by


Tags : , , , , , ,

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

안드로이드 4.4 킷켓(kitkat)에서 5.0 롤리팝(lollipop)으로 업데이트.

안드로이드 롤리팝 버전이 나온 지 한참인데 넥서스 5에서 자동 업데이트가 되지 않아서 주말을 맞아 수동으로 업데이트했다.

구글 넥서스 5 롤리팝 버전 수동 업데이트 순서

  1. 우선 중요 파일과 앱을 백업한다. 지워져도 서운하지 않을 파일만 남긴다.
  2. https://developers.google.com/android/nexus/images#hammerhead 에서 안드로이드 5.0.1 (LRX22C)이미지를 받아 압축을 푼다.
  3. 넥서스 5 전원이 꺼진 상태에서 전원+소리 크게+소리 작게 버튼을 동시에 눌러 빠른부팅모드(Fastboot)로 진입한다.
  4. USB 케이블을 이용하여 컴퓨터에 넥서스 5를 연결한다. (usb 3.0 포트에 꼽으면 fastboot에서 인식을 못 하기도 하니 usb2.0포트에 꼽는다.)
  5. 심호흡을 한다.
  6. flash-all.sh 스크립트를 실행하여 넥서스5 에 이미지를 넣는다. (윈도우즈 사용자는 flash-all.bat)

스크립트를 살펴보면 아래와 같다.
fastboot flash bootloader bootloader-hammerhead-hhz12d.img
fastboot reboot-bootloader
sleep 5
fastboot flash radio radio-hammerhead-m8974a-2.0.50.2.22.img
fastboot reboot-bootloader
sleep 5
fastboot -w update image-hammerhead-lrx22c.zip

부트로더, 라디오, lrex22c버전 이미지 순서로 설치한다.
여기서 아차 싶었다.
커스텀 리커버리를 통해 롬을 설치할 땐 Wipe 메뉴에서 지울 데이터를 선택하여 지우고 롬을 올리면 되는데 이건 싹. 밀어버린다.
내부 저장소에 저장된 파일까지 몽땅.
백업을 해 두긴 했으나 티타늄 백업으로 백업한 apk는 컴퓨터로 옮겨두지 않았는데 모두 다 지워졌다.
새해는 새 기분으로.
폰을 새로 산 기분이다!
혹시나 해서 연락처와 사진은 컴퓨터로 옮겨 두어서 다행이다. 비록 즐겨듣던 노래는 모두 사라졌지만.
아무튼, 이제 넥서스5가 공장 초기화 상태가 되었다.
내친김에 롬도 새로 깔고 커널도 바꾸어 깔아보자.

TWRP recovery 설치

공장초기화 되었기 때문에 우선 커스텀 리커버리를 설치해야 한다.
openrecovery-twrp-2.8.4.0-hammerhead.img
(https://www.androidfilehost.com/?fid=95897840722643055)파일을 받아 fastboot로 설치한다.
fastboot flash recovery openrecovery-twrp-2.8.4.0-hammerhead.img
fastboot모드에서 음량버튼으로 recovery를 선택하여 TWRP로 들어간다.

Cataclysm 롬 설치.

  1. http://forum.xda-developers.com/google-nexus-5/orig-development/rom-cataclysm-nexus-5-t2518660 페이지에서 롬을 내려받는다.
  2. TWRP에서 Wipe메뉴로 가서 internal storage를 제외한 데이터를 날려준다.
  3. 전원을 끈다.
  4. TWRP recovery로 진입한다.
  5. Install 메뉴에서 Cataclysm이미지를 설치한다.
    Wipe후 바로 설치하려고 하면 오류가 발생한다.

ElementalX 커널 설치

  1. http://elementalx.org/devices/nexus-5/에서 ElementalX-N5-2.05를 다운받는다.
  2. TWRP recovery로 진입한다.
  3. Install 메뉴에서 ElementalX커널을 설치한다.
    Cataclysm을 설치하고 재부팅 없이 바로 ElementalX커널을 설치해도 된다.

설치 후기

가벼운 느낌이다.
기분 탓인지 터치 감도가 떨어지는 것 같다.
Cataclysm + ElementalX가 배터리 소모가 적다는데, 아직 피부로 와 닿지는 않는다.

음악이 다 지워져서 허전하다.
낡은 PC를 뒤적거리다가 즐겨찾기 음악 폴더를 발견했고, 십 년도 더 된 노래를 옮겨 담았다.
집을 나서 음악을 틀었더니 이어폰 선을 타고 귀로 퍼진다.
흥겨운 리듬을 타고 머리가 절로 흔들거린다.
덕분에 나도 이십 대로 돌아간 듯 발걸음이 가벼워졌다.

One T Cool T - The Magic Key



by


Tags : , , , , ,

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

매번 반복되는 지루한 일상(환경 구축)은 가라. Docker.

작년 여름에 Docker를 전해 들었다.
‘거 참 괜찮네.’란 생각이 들었지만 직접 써본 건 바닥에 낙엽이 깔리고 나서였다.
그래도 이제는 손에 좀 익었기에 Docker에 대해 몇 자 적어본다.

소프트웨어 개발을 대략적인 과정은 다음과 같다.
환경 구축(개발) -> 개발 -> 환경 구축(테스트) -> 테스트 -> 환경 구축(배포) -> 배포
Ax -> B -> Ay -> C -> Az -> D

환경 구축이라는 작업이 반복적으로 이루어진다.
환경을 구축하는 것은 중요하지만, 어지간히 귀찮아서 여러 번 다시 하기 싫은 일이다.
그래서 예로부터 이런 환경 설정을 쉽게 도와주는 도구들이 개발자를 도왔다.
윈도즈 사용자라면 지금 환경을 통째로 구워서 어디서나 같은 작업 환경을 금세 되돌릴 수 있는(예를 들면 게임과 애드온이라든가...) 노턴 고스트라는 도구를 익히 들어봤을 것이다. 웹 개발자라면 APM(Apache + Php + Mysql) 환경 구축을 돕는 LAMP, WAMP, MAMP라는 녀석들과 가깝게 지냈을 것이다. 자바와 루비, 파이썬, 노드JS 등도 인기가 많아서 호스팅 업체에서는 이들을 위한 환경을 미리 구축하고는 OO호스팅, XX호스팅이라며 상품을 만들어 팔기도 한다. 그렇지만 수많은 개발 언어(http://en.wikipedia.org/wiki/List_of_programming_languages)중에 별로 인기가 없는 언어로 자신만의 환경을 구축하려면? 그리고 이런 환경을 다른 머신에 또 구축하려면? 우공(愚公)이 산을 옮기듯 삽질을 아주 여러 번 해야 한다. 이건 너무 불공평하다. 지금은 민주주의 시대인데, 소수 언어 사용자도 편리할 권리가 있잖은가? 그래서 Vagrant(https://www.vagrantup.com/)라는 멋진 녀석이 나왔다. Vagrant를 이용해서 환경을 한 번 구축해 두면, 다른 머신에서 언제나 꺼내 쓸 수 있다. 다만 여전히 문제가 있었으니 가상머신에 종속되기 때문에 덩치가 크고, 자원을 많이 잡아먹는다. 그러니 넉넉지 못한 환경에서 vagrant를 돌리면 만족스러운 성능을 기대하기 어렵다. 이에 반해 Docker는 LXC(http://en.wikipedia.org/wiki/LXC)를 통해 kernel cgroup 과 namespacing을 이용하니 훨씬 가볍다. 다만 이는 리눅스 시스템에서 사용할 때 이야기고, 애플 OS X나 마이크로소프트 Windows에서는 boot2docker(https://github.com/boot2docker/boot2docker)등의 도움을 받아야 한다. Vagrant + Docker도 썩 괜찮은 조합이라고 한다.

Docker를 써보자.

설치

https://docs.docker.com/installation/ 문서를 참조한다.

Arch 리눅스

sudo pacman -S docker
sudo systemctl enable docker

Arch 리눅스에서 sudo 없이 docker를 사용하고 싶다면 아래 커맨드를 실행한다.

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

gpasswd -a <user> docker

Ubuntu 리눅스

문서(https://docs.docker.com/installation/ubuntulinux/) 에 따르면
Ubuntu-maintained Package와 Docker-maintained Package가 있다.
Ubuntu-maintained Package를 설치하면 버전이 낮아서 Dockerfile에서 설정한 ENV를 WORKDIR에서 인식하지 못하는 문제가 발생한다.

Ubuntu 리눅스에서 sudo 없이 docker를 사용하고 싶다면 아래 커맨드를 실행한다.

groupadd docker
gpasswd -a <user> docker
service docker.io restart

그리고 로그아웃하고 다시 로그인한다.(재부팅)

설치 오류 해결

Your kernel does not support cgroup swap limit

/etc/default/grub
GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"

$ sudo update-grub
그리고 재부팅한다.


error: cannot run ssh: No such file or directory fatal: unable to fork

경로 문제이다. 경로(path)에 다음을 추가한다.
/nvm/{nodeJS version x.xx.xx}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin


Docker를 익히는데 도움이 되는 문서

http://blog.nacyot.com/articles/2014-01-27-easy-deploy-with-docker/
http://forum.docker.co.kr/t/docker-docker-howto/68
https://www.docker.com/
http://dockerbook.com/
https://coderwall.com/p/2es5jw/docker-cheat-sheet-with-examples
https://github.com/wsargent/docker-cheat-sheet

자주 쓰는 Docker 명령어

Dockerfile 빌드(build)

Dockerfile이 있는 디렉토리에서 실행한다. --no-cache는 캐쉬를 사용하지 않는 옵션이다.
docker build -t "<tag : user/repository>" --no-cache .
사용 예)
docker build -t "dorajistyle/flask-canjs-i18n-boilerplate" --no-cache .

entry point 덮어쓰기

주로 이미지나 컨테이너에서 bash 쉘을 실행하기 위해 쓴다. -it는 STDIN을 허용하는 pty를 여는 옵션이다.
docker exec -it <container-id> <command>
docker run -it <image-id> <command>
docker run -it --entrypoint <command> <image-id>

cannot execute binary file 오류가 뜨면 아래 커멘드를 쓴다.

docker run -it --entrypoint <command> <image-id> -s

이미지 실행

--publish, -p 옵션은 컨테이너의 포트를 호스트포트로 넘겨준다. 6060:8080이면 호스트에서 6060포트로 접속하면 컨테이너의 8080포트로 연결된다.
--name 옵션은 컨테이너에 이름을 붙여준다.
--rm 옵션은 실행된 컨테이너가 중지되면 컨테이너를 자동으로 지워준다.
-d 옵션은 데몬으로 실행한다.
docker run --publish <host-port>:<container-port> --name <container-name> --rm <image-name>
docker run -dp 6060:3001 <host-port>:<container-port> <image-name>

사용 예)
docker run --p 6060:5050 --name fcib --rm dorajistyle/flask-canjs-i18n-boilerplate
docker run -dp 6060:3001 my-image

실행중인 컨테이너 중지

docker stop <container-id>

이미지에 태그 달기

docker tag "user/tag"

docker.io에 이미지 등록하기

docker허브에 등록한뒤에 로그인하고 push하면 된다. image-tag는 / 형식으로 쓴다.
docker login
docker push <image-tag>

쓰지 않는 컨테이너와 이미지 지우기.

docker stop $(docker ps -a -q) && docker rm $(docker ps -a -q) && docker images --no-trunc| grep none | awk '{print $3}' | xargs -r docker rmi

docker ps의 -a옵션은 모든 컨테이너를 보여주는 것이고, -q옵션은 컨테이너의 다른 정보 없이 id만 보여주라는 것이다.
위 커멘드는 3 부분으로 나뉜다.
docker stop $(docker ps -a -q) // 모든 컨테이너 중지
docker rm $(docker ps -a -q) // 모든 컨테이너 삭제
docker images --no-trunc| grep none | awk '{print $3}' | xargs -r docker rmi // 알수 없는 이름의 모든 이미지를 지운다.

컨테이너 IP주소 받아오기

docker inspect <container-id>
docker inspect -f '{{ .NetworkSettings.IPAddress }}' <container-id>
docker inspect <container-id> | grep IPAddress | cut -d '"' -f 4
docker run <image-id> ip -4 -o addr show eth0


Dockerfile 잘 쓰기

  • 캐쉬를 잘 활용한다.
  • 태그를 쓴다.
  • base이미지로 작은 것을 쓴다. (ubuntu 보다는 debian)
  • 공통된 작업은 묶어서 한다. (예 : RUN apt-get install A B C D E F)
  • 용도에 맞게 base이미지를 만들어서 활용한다. (RoR용 base, 파이썬용 base, Golang용 base등)

Docker 빌드 자동화

Docker허브를 이용하면 github.com이나 bitbucket.org의 저장소가 변경될때마다 자동으로 빌드되도록 할 수 있다.
http://docs.docker.com/userguide/dockerrepos/

Docker Remote API의 웹 인터페이스

https://github.com/crosbymichael/dockerui

CI(Continuous Integration) 도구

https://github.com/drone/drone
https://github.com/Strider-CD/strider

Docker를 쓰면서 궁금했던 점이 두 가지 있다. 하나는 'Dockerfile에서 Private Repository를 clone하려면 어떻게 해야 할까?' 이고, 또 다른 하나는 '확장은 어떻게 해야 할까?'이다.

Private 저장소를 Dockerfile에서 불러오기.

스텍오버플로우 질문을 찾아보니 아래 처럼 하면 된다고 한다.

# private key를 복사한다.
ADD id_rsa /root/.ssh/id_rsa
# known_hosts 파일을 만든다.
RUN touch /root/.ssh/known_hosts
# bitbuckets키(다른 저장소를 이용한다면, 다른 저장소의 키)를 known_hosts에 추가한다.
RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

위 방법은 Dockerfile과 id_rsa가 같은 경로에 있어야만 한다.
단일 Dockerfile만으로는 방법이 없을까?
RUN command안에 키를 넣어 버리는 것이다. Dockerfile이 유출되면 Private Key도 노출된다는 단점이 있지만, 이는 위의 방법도 마찬가지다. Dockerfile과 Private key 파일이 함께 있을테니까. 그래도 보안을 위해서 Dockerfile에 사용할 키는 저장소에서 read권한만 가진 배포용 권한만 주는것이 좋다.
아래처럼 넣어주면 된다.
RUN mkdir -p /root/.ssh && str="-----BEGIN RSA PRIVATE KEY-----blahblahblah-----END RSA PRIVATE KEY-----" && echo | sed "i$str" > /root/.ssh/id_rsa && \
echo "ssh-rsa blapublahpublah" > /root/.ssh/id_rsa.pub && \
chmod 600 /root/.ssh/id_rsa && \
printf "Host bitbucket.org\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config


Docker를 이용한다면 확장은 어떻게 해야 할까?

문서(http://www.centurylinklabs.com/auto-loadbalancing-with-fig-haproxy-and-serf/)에서
http://www.fig.sh/http://www.haproxy.org/ 그리고 https://www.serfdom.io/를 이용한 로드벨런싱을 설명하고 있다.
그리고 문서(http://stackoverflow.com/questions/18285212/how-to-scale-docker-containers-in-production)에 따르면, 확장을 돕는 다양한 서비스가 나와있으니, 구미에 맞는 서비스를 이용하면 되겠다.
아마존의 Elastic Beanstalk에서도 Docker를 지원하므로, AWS에 익숙하다면 이를 이용하면 편리하다. 이 내용은 추후에 다시 다루겠다.


확장과 로드밸런싱을 돕는 도구들


참고자료



by


Tags : , , , ,

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

월풍도원 블로그의 컨텐츠를 정리한 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
vmap "+yi
vmap "+c
vmap c"+p
imap +
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


disable USB autosuspend

vim /etc/laptop-mode/conf.d/usb-autosuspend.conf
CONTROL_USB_AUTOSUSPEND="0"


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

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


GUI 유틸리티

pacman -S transmission-gtk
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

눈 피로를 덜어주는 Redshift

https://wiki.archlinux.org/index.php/Redshift
pacman -S redshift

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
}


yaourt 설정

~.yaourtrc

yaourt 패키지 업데이트

yaourt -Syua

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

특정 디렉토리에서 Shell 띄우기

bash -c 'cd ~/specific/dir; exec "/bin/bash"'

문제 해결

Pacman이나 Yaourt로 패키지 설치시 error: failed to commit transaction (conflicting files)

pacman -S --force $package

재부팅을 하면 화면이 제대로 동작하지 않고, /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>

NTFS 파티션 마운트 오류 해결

pacman -S ntfs-3g
ntfsfix /dev/ntfs-partition-name


USB를 Fat32로 포멧

pacman -Sy dosfstools
fdisk -l
mkdosfs -F 32 -I /dev/usb-partition-name


외장 디스크가 readonly로 뜰 때

sudo su -
df -Th
umount /media/mounted-name
dosfsck -a /dev/partition-name


bash: fork: retry: No child processes

/etc/security/limits.conf 파일에 다음 추가
username soft nofile 4096
username hard nofile 65536

/etc/sysctl.d/99-sysctl.conf 파일에 다음 추가
fs.inotify.max_user_watches = 20000
fs.file-max = 800000

현재 쉘 세션에서만 임시로 open files 크기를 늘려줄 때는 아래 명령어를 실행
ulimit -n 4096


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 : , , , , , , ,

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