AWS Summit 2017. IoT와 AI.


AWS에서 많은 서비스를 제공하고 있지만, 지금 사용하는 서비스는 몇 가지 되지 않는다.
아마존 웹 서비스를 쓰면서 서비스 운영에 대한 부담이 많이 줄었으니 또 좋은 서비스가 눈에 띄면 써보고 싶은데,
문서 찾기가 영 까다롭다.
그래서 가끔은 이런 행사에 가서 정보를 얻는다.
이틀 동안 진행하는 행사였는데, 목요일 하루 오후에만 잠깐 다녀온 게 좀 아쉽지만,
제일 관심 있던 IOT와 AI 세션을 들었으니 만족한다.
이번 행사에서 가장 흥미로웠던 건 오프라인 환경에서 IOT 기기의 소통을 돕는 AWS greengrass였다.
이를 통해 정보기술 서비스를 적용하기 어려웠던 분야에 혁신이 이루어지길 기대해본다.

AWS Summit 2017 서울, 메모

AWS 기반 고급 하이브리드 IT 디자인

Direct connect (https://aws.amazon.com/ko/directconnect/)

비용

Port 사용비용/시간 + 데이터 전송료
데이터 IN $0, 데이터 아웃 - 리전별 상이
회선(전용선/MPLS) 비용
로케이션 상면 임대비용(필요시)
트래픽이 많으면 전용선을 쓰는게 오히려 비용 절감이 된다.

성능

1 Gbps 10Gbps
DX파트너를 통해 100, 200, 300, 400, 500 Mbps 까지 가능
VPC 까지 통신할 때는 VPC peering을 사용한다. (dev, test, production VPC)
원하는 수준의 네트워크 가용성을 가질 수 있다.

Amazon SNS로 지속적 관리가 가능한 대용량 푸쉬 시스템 구축 여정

레거시

GCM, APNS 이용해서 1000건씩 끊어 보냈음.
시간 오래걸리고 상태와 모니터링 어려움

SNS (https://aws.amazon.com/ko/sns/)

Topics : 어플리케이션 엔드포인트들이 구독 단위로 그루핑 되어있음
Application : 플랫폼 별 토큰
Subscriptions : 어플리케이션이 토큰을 구독하는 정보

aws 콘솔에서 csv토큰 등록할 때 오류발생 : cli나 api를 이용하자.
이벤트가 발생할 때마다 SQS에 넣고 람다로 파싱해서 로그를 관리 (예 : 발송 이벤트가 발생하면 해당 토큰이 발송 완료되었다는 것을 표시해두고 중복 전송을 막는다.)
병렬처리할 때 동일 데이터를 끌고가면 중복 푸쉬가 발생하는걸 염두에 두자.
APNS 어플리케이션 인증은 1년마다 만료되므로 미리미리 갱신해두자.
SNS - CloudWatchLogs 기록 IAM 설정해두자.

그룹 전송

조건에 일치하는 사용자 목록을 뽑아서 큐에 넣고 람다를 통해 SNS로 발송
회원 가입할 때 토픽을 정의해둔다.

AWS와 Docker Swarm을 이용한 쉽고 빠른 콘테이너 오케스트레이션

Docker swarm (https://docs.docker.com/engine/swarm/)

클러스터 구성 / ECS보가 몇가지 나은 기능도 있다.
멀티메니저 노드 지원
다양한 서비스를 연결해 사용해야 할 때 고려해볼 만 하겠다.
Docker for AWS (Cloud formation)
오토스케일링 설정 가능
클라우드와치 지원

docker network

동일 네트워크에 컨테이너를 등록
Ingress Network : 모든 노드에 포트를 오픈한다.
visualizer service로 각 노드의 상태를 알 수 있다.

AWS IoT 기반 사물 인터넷 아키텍쳐 구현하기

https://aws.amazon.com/ko/iot/

기능

Device gateway : MQTT와 HTTP(1.1)를 이용한 Thing과의 커뮤니케이션
Device sdk : 연결, 인증, 메시지교환
Rules Engine : 규칙 기반으로 메시지 변환 및 AWS 서비스로 전달 (sql로 토픽 필터 정의)
Rule Engine Action :
하나의 토픽에 여러 룰을 적용해서 연동
Shadow : 기기가 오프라인일 때 마지막 상태를 알아내거나 다음 동작을 저장해둠. (일종의 캐쉬로 보면 되겠다. 파이어베이스db처럼)

구성 축

Thing : Sense, act
Cloud : storage, computing
Intelligence : analysis

AWS Greengrass(https://aws.amazon.com/ko/greengrass/)

로컬 이벤트에 신속히 반응할 수 있음
오프라인 운영가능
디바이스에서 데이터 처리 가능
클라우드 비용 절감

AWS Greengrass 구성

  • 로컬 브로커
  • 로컬 람다
  • 로컬 디바이스 쉐도우
데이터 온도에 따라 다른 접근이 필요하다.
Hot - Kinesis, Warm - Lambda , Cool, Cold

Amazon AI 서비스를 통한 스마트 애플리케이션 개발

https://aws.amazon.com/amazon-ai/

Polly

텍스트를 음성으로 변환
SSML 지원 : 음선 합성을 위한 W3C레서 정한 XML 기반 언어 규약
Lexicons : 개발자가 단어의 실제 발음을 정의
텍스트 - 어떻게 읽을지 텍스트 문장 - 발음으로 변환 - 높낮이 규정 - 음성 스트리밍으로 변환
MP3로 다운받아 재사용 가능
cli, sdk로 사용 가능
aws polly
백만문자당 $4

Amazon Recognition API

이미지에서 객체 및 장면을 탐지해서 json으로 반환
안면인식, 비교
민감한 정보를 포힘하고 있는지 알려줌

Amazon Lex

쉬운 쳇봇 구현
콘솔에서 정의해서 바로 런칭 가능
versioning, alias 제공



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

파이어베이스 커스텀 토큰을 이용한 데이터베이스 접근권한 설정하기


파이어베이스 데이터베이스에 조건에 따라 접근권한을 다르게 하려고 커스텀 토큰을 이용하게 되었다.
커스텀 토큰을 만들고 파이어베이스에 규칙을 적용한 다음 테스트를 해보려고 했는데 REST API에 JWT토큰을 아무리 넣어봐도 작동하지 않았다.

?auth=CUSTOM-TOKEN 파라미터로도 넣어 보았고,
Authorization: bearer CUSTOM-TOKEN 헤더로도 넣어 보았지만

"error" : "Permission denied"
"error" : "Expected an ID token, but was given a custom token." 같은 오류만 보여줄 뿐이었다.

REST에서 커스텀 토큰을 사용할 방법을 한참 찾다가 FireBase Rest with auth query param not working(http://stackoverflow.com/questions/39117237/firebase-rest-with-auth-query-param-not-working)이라는 글에서 답을 찾았다.

REST API 에서는 커스텀 토큰을 사용할 수 없다.

REST에서 커스텀 클레임을 사용하기 위해서는, auth_variable_override 파라미터를 사용해야 한다.
{"uid":"6LiF16Dm0hNB9XO61UR1KM5Jeun2"}
위의 uid를 사용한다면 아래처럼 요청해야 한다.
$ curl "https://dbname.firebaseio.com/test.json?access_token=&auth_variable_override=%7B%22uid%22%3A%226LiF16Dm0hNB9XO61UR1KM5Jeun2%22%7D" {" 1213314":{"alanisawesome":"Alan Turing"}}


결국 파이어베이스의 커스텀 토큰을 테스트하려면 파이어베이스 라이브러리를 사용해야 한다.
그래서 파이어베이스 커스텀 토큰 테스트를 위한 예제 프로젝트를 node.js로 간단히 만들었다.
아래 예제를 따라 하면 파이어베이스의 커스텀 토큰으로 데이터 베이스 접근 권한을 제어하는 흐름을 볼 수 있다.

커스텀 토큰으로 데이터 베이스 접근 권한 설정하기(https://github.com/dorajistyle/firebase-custom-token-sample/blob/master/readme-ko.md)


참고

https://firebase.google.com/docs/admin/setup
https://firebase.google.com/docs/auth/cpp/custom-auth
https://firebase.google.com/docs/auth/admin/create-custom-tokens
https://firebase.google.com/docs/reference/security/database
http://stackoverflow.com/questions/37426093/using-custom-tokens-to-make-rest-requests-to-fb-db-as-an-admin
http://stackoverflow.com/questions/39117237/firebase-rest-with-auth-query-param-not-working
https://jwt.io/



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

젠킨스 CI에서 레일즈+Postgres 테스트하기


젠킨스는 오픈소스 지속적 통합관리(Continuous Integration) 도구로 자바기반이다.

소스를 git이나 svn 같은 형상관리(CM : configuration management) 서버에 올리면, 그때마다 자동으로 테스트도 하고, 빌드도하고, 작업이 잘 끝났다고 알림도 주는 도구다.

자바기반이기 때문에 다른 언어로 개발된 애플리케이션을 젠킨스에서 테스트 하려면 따로 환경 설정이 필요하다. 이번엔 루비 온 레일즈로 만들어진 애플리케이션 테스트를위해 환경을 설정해 보았다.

레일즈 테스트용 젠킨스 도커 설정은 https://github.com/dorajistyle/jenkins-rails-postgres-docker 에서 볼 수 있다.

우선 아래 명령어로 소스를 다운 받는다.

git clone https://github.com/dorajistyle/jenkins-rails-postgres-docker.git


그리고 아래 명렁어로 도커 컨테이너를 빌드하면 젠킨스가 실행된다. docker-compose.yml에 나와있듯이 docker compose를 이용해서 postgres와 redis를 jenkins와 함께 실행하도록 하였다.

docker-compose up


젠킨스에서 레일즈를 테스트하기 위한 순서는 다음과 같다.

  1. 터미널에서 admin암호를 복사해서 젠킨스에 붙여 넣는다.
  2. 유저 정보를 입력해서 젠킨스를 시작한다.
  3. Multi-configuration 프로젝트를 만든다.
  4. Source Code Management 에서 git를 선택한다.
  5. 아래 url을 Repository URL 필드에 붙여넣는다.
    https://github.com/dorajistyle/rails-postgres-sample-for-jenkins

    만약 오픈소스가 아닌 프로젝트를 테스트 하려면, Credential을 추가해 줘야 한다.
    Add를 눌러 Username and password방식을 선택하고, username에는 github ID를 넣고 password에는 https://github.com/settings/tokens에서 생성한 토큰을 넣으면 된다.
  6. Build Environment에서 rbenv build wrapper체크박스를 선택한다.
    The Ruby version에는 2.3.1을 넣고,
    Preinstall gem list에는 bundler,rake,execjs를 넣는다.
  7. Add build step 샐랙트박스에서 Execute shell를 선택한다.
    Command필드에 아래 명령어를 붙여 넣는다.
    bash jenkins-test.sh
  8. 만약 빌드가 될 때 마다 슬랙으로 알림을 주고 싶다면, 플러그인을 설정해줘야 한다.
    우선 github 프로젝트의 설정에 젠킨스 플러그인을 추가해준다.
    Settings--> Webhooks&Services-->Service--> Add Services--> Choose "Jenkins (GitHub plugin)"
    에서 추가하고 아래 주소를 넣어준다.
    http:///github-webhook/
    https://.slack.com/apps/A0F7VRFKN-jenkins-ci 에서 Jenkins CI 앱 설정을 해준다.
    Post-build Actions의 Add post-build action 선택상자에서 Slack Notifications를 선택하고 환경 정보를 넣어준다.
    토큰은 슬랙 앱 설정에 나온 토큰을 넣어주면 된다.
  9. 설정을 저장하고 프로젝트의 사이드메뉴에서 Build Now를 클릭하여 테스트한다.

Docker compose로 띄운 
젠킨스에서 레일즈 테스트가 잘 돈다.

* rails 설정의 database.yml에는 docker-compose로 설정한 컨테이너 이름(예제 : dorajistyle-postgres)을 쓰고,
config.yml의 redis설정에도 마찬가지로 컨테이너 이름(예제 : dorajistyle-redis)를 써야 한다.


* git fetch 타임아웃 발생시 해결
Source Code Management > Git > Additional Behaviors > Advanced checkout behaviors / Advanced clone behaviors > Timeout (in minutes)



by


Tags : , , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

Multi-container 도커 애플리케이션 쉽게 쓰기. Docker Compose


Docker는 참으로 편리한 도구다. Dockerfile만 한번 잘 작성해 두면, 두고두고 잘 쓸 수 있다. 그러나 한 가지 아쉬운 점이 있다면, 복잡한 서비스는 Dockerfile이 지나치게 길어진다는 것이다. 데이터베이스와 캐시, 애플리케이션 설정을 한데 모아두면 오류가 났을 때 무엇이 문제인지 찾기도 어렵다.
그래서 각각의 설정을 따로 만들어서 실행 시에 --link 옵션으로 연결하기도 하지만, 귀찮은 일이다.
Docker compose는 그런 귀찮음을 줄여준다. 아래 docker compose 설정 파일을 보자.


docker-compose.yml
version: '2'
services:
postgres:
container_name: mypostgres
image: postgres
ports:
- "5432:5432"
redis:
container_name: myredis
image: redis
ports:
- "6379:6379"
webapp:
build: .
container_name: myapp
restart: always
ports:
- "80:8080"
depends_on:
- postgres
- redis


이렇게 설정 파일을 만들고,
docker-compose up
명령어만 실행하면 애플리케이션을 실행하기 전에 postgres와 redis를 띄우고 나서, webapp 컨테이너를 띄워준다.
webapp에서 해당 컨테이너에 접속하려면 host에 container_name을 넣어주면 된다.
예를 들어 postgres에 접속하려면 host에 mypostgres를 넣어주면 된다.
docker compose 덕분에 도커 컨테이너 관리의 신세계가 열렸다.

아마존 AWS의 EC2 Container service 에서도 docker compose 파일을 지원하기 때문에, 쉽게 배포할 수 있다.
다만 로컬 이미지를 지원하지 않으므로 Amazon EC2 Container Registry(ECR)에 이미지를 올려 사용해야 한다.
만약 배포해야하는 multi-container docker가 많다면 ECS를 고려해볼 만 하다.
하지만 ECS task를 실행하기 위해서는 인스턴스를 하나 올려야 하므로, 올려야 할 서비스가 많지 않다면 그냥 EC2 인스턴스 하나에서 docker-compose up 명령어를 사용해 띄우는 것이 경제적이다.
꼭 ECS를 사용하지 않더라도 오픈소스가 아닌 이미지 저장용으로 ECR은 쓸만하다.
따로 Docker registry를 위한 인스턴스를 띄우지 않아도 되고, 스토리지 요금과 데이터 전송 요금만 사용한 만큼 내면 되기 때문에 간편하다.


참고자료

https://docs.docker.com/compose/rails/
https://docs.docker.com/compose/compose-file/
https://docs.docker.com/compose/startup-order/

AWS ECS 관련

http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html
https://aws.amazon.com/ko/ecr/
http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI_installation.html
http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI_Configuration.html
https://github.com/aws/amazon-ecs-cli
https://aws.amazon.com/ko/ecr/pricing/?nc1=h_ls



by


Tags : , , , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

아치리눅스 기반 배포판. Antergos 설정.


그동안 아치(arch)리눅스 기반의 manjaro를 쭉 써오다가 Antergos로 갈아탔다.
둘 다 아치리눅스기반이라 쓰던 설정을 그대로 써도 된다.
어쩐 일인지 한글 입력이 잘 되지 않아 입력기를 uim에서 dasom으로 바꾸었다.
하드웨어 사양이 좋아져서 DE도 xfce에서 gnome으로 갈아탔다.

다솜 한글 입력기 설치

yaourt -S dasom-git
yaourt -S dasom-gtk-git
yaourt -S dasom-jeongeum-git
yaourt -S dasom-qt-git

.xprofile 설정

IM="dasom"
export GTK_IM_MODULE=$IM
export XMODIFIERS=@im=$IM
export QT_IM_MODULE=$IM
export QT4_IM_MODULE=$IM
export XIM=$IM
dasom-daemon
dasom-indicator
gsettings set org.gnome.settings-daemon.plugins.keyboard active false
gsettings set org.gnome.settings-daemon.plugins.xsettings overrides "{'Gtk/IMModule':<'dasom'>}"


설정 적용 확인

  1. export | grep IM
    declare -x GTK_IM_MODULE="dasom"
    declare -x QT4_IM_MODULE="dasom"
    declare -x QT_IM_MODULE="dasom"
  2. export | grep XMODIFIERS
    declare -x XMODIFIERS="@im=dasom"

Antergos에 설치한 아치리눅스 패키지 목록

ack : 검색
android-apktool : a tool for reengineering Android apk files
android-sdk : 안드로이드 sdk
android-sdk-build-tools : 안드로이드 sdk 빌드 툴
android-sdk-platform-tools : 안드로이드 sdk 플랫폼 툴
android-udev
avidemux-cli-git : 영상 편집
avidemux-core-git : 영상 편집
avidemux-qt4-git : 영상 편집
aws-cli : aws 커맨드라인 클라이언트
chromium : 웹 브라우저
chromium-pepper-flash : 크로미움 플래시 플러그인
dasom-git : 한글 입력기
dasom-gtk-git : 한글 입력기
dasom-jeongeum-git : 한글 입력기
dasom-qt-git : 한글 입력기
docker : 도커
dosfstools : 도스 파일시스템 유틸
epdfview : pdf 뷰어
evince : 문서 뷰어
evolus-pencil-svn : GUI 프로토타이핑 툴
fdupes : 중복파일 제거
firefox : 웹 브라우저
firefox-raismth : 파이어폭스 실버라이트 플러그인
focuswriter : 글쓰기용 도구
gedit : 에디터
genymotion : aos 시뮬레이터
gimp : 이미지 편집기
git : git
hugo : static page generator
marble : 지구본
mariadb : mariadb
meld : diff툴
mercurial : 버전관리도구
mysql-workbench : mysql 관리툴
nano : 에디터
nautilus-share : nautilus 파일 공유
ncdu : 하드 용량 체크
noto-fonts : noto 폰트
numix-frost-themes : numix 테마
numix-icon-theme : numix 테마
numix-icon-theme-square : numix 테마
openssh : ssh
oxygen-icons : oxygen아이콘
pgadmin3 : postgres 관리 툴
pidcat : logcat보기 쉽게.
playonlinux : wine 사용을 쉽게.
poppler-data : pdf 랜더링 라이브러리용 인코딩 데이터
postgis : postgis
postgresql : postgrel
profile-cleaner : 웹브라우저 프로필 사이즈 줄이기
profile-sync-daemon : 브라우저 프로파일 싱크(속도개선)
qps : 프로세스 메니저
qupzilla : 웹브라우저
redis : 메모리기반 key-value 저장소
redshift : 블루라이트 필터
s3cmd : s3 커맨드
sbt : 스칼라 빌드툴
sed : 문자열 처리
steam : 스팀 게임
sublime-text-nightly : 에디터
terminator : 터미널
tilda : 터미널
tomighty : 뽀모도로 타이머
tribler : 토렌트
ttf-baekmuk : 글꼴
ttf-bitstream-vera : 글꼴
ttf-dejavu : 글꼴
ttf-freefont : 글꼴
ttf-google-fonts : 글꼴
ttf-liberation : 글꼴
ttf-nanum : 글꼴
unetbootin : 부팅usb 제작용
unity-editor : 유니티 에디터
unrar : 압축해제
unzip : 압축해제
vi : vi에디터
viewnior : 이미지 뷰어
vim-colorsupport : 빔 색상지원
vips : 이미지 처리 라이브러리
virtualbox-guest-dkms
virtualbox-guest-modules
virtualbox-host-dkms
virtualbox-host-modules
visual-studio-code : 코드 에디터
vlc : 비디오 재생
wine : 와인(윈도우즈용 프로그램 실행)
wine-mono
wine_gecko
winetricks
xnviewmp : 이미지 편집기 및 뷰어

문제 해결

Pacman 오류 (invalid or corrupted package (PGP signature))

archlinux-keyring 패키지를 업데이트 한다.

Antergos



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

안정성에 중점을 둔 리눅스 배포판. NixOS

아치 리눅스를 쓰다 보면 어느 날 갑자기 부팅이 안 되곤 했다.
업데이트하고 전원을 끈 다음에 일어난 일이다.
어떨 때는 디스플레이가 안 켜지고,
어떨 때는 무선 인터넷이 안 잡힌다.
업데이트하면서 뭔가 문제가 발생한 거다.
그럴 때마다 괜한 데 시간을 보내면 짜증이 나고,
그냥 맘 편히 맥을 쓸까 하는 마음이 든다.
그러나 리눅스는 또 나름 리눅스만의 매력이 있으니 다시 마음을 진정하고 고쳐나간다.
NixOS는 업그레이드 후에 발생하는 이런 문제를 막아줄 획기적인 리눅스 배포판이다.
업그레이드해서 문제가 생기면 rollback으로 되돌리면 된다!
그리고 NixOS 설정파일에서 모든 설정을 관리한다.
/etc/fstab이라든가 /etc/passwd같은 파일을 직접 손댈 필요가 없고(읽기 전용으로 수정 불가), 하나의 파일에서 모든 환경 설정을 관리한다.
환경설정을 담은 설정파일 하나면 여러 대의 머신이 동일한 환경으로 세팅된다.
참 매력적인 배포판이다.
그러나 환경을 마음대로 뜯어고칠 수 없다는 건, 그만큼 제약도 많다는 이야기다.
어디서 바이너리 하나 받아다가 쓰려고 해도 patchelf등을 이용해 패치를 해줘야 한다.
NixOS패키지 매니저에 꽤 많은 패키지가 있지만, 아치나 우분투 패키지에 비하면 한참 모자라다.
하드웨어를 여러 군데에 동일 세팅으로 배포해야 하는 경우에는 쓸만하겠지만,
계속 패키지를 설치하고 지우고, 환경설정을 바꾸는 데스크톱용으로는 아쉬운 배포판이다.

참고자료

https://nixos.org
https://nixos.org/nixos/manual/
https://nixos.org/nixos/manual/options.html
https://en.wikipedia.org/wiki/NixOS
http://funloop.org/post/2015-08-01-why-i-use-nixos.html
https://nixos.org/wiki/Cheatsheet
https://nixos.org/wiki/Install/remove_software



by


Tags : , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

아치 리눅스에 2D/3D 개발 엔진 유니티(Unity) 설치하기


유니티는 윈도우와 맥만을 공식 지원하기 때문에 이번에 노트북을 바꿀 때 고민을 좀 했다.

'뭐 내가 유니티를 쓸 일이 얼마나 있겠어? 그냥 리눅스 머신으로 가자.'

그러나 새 리눅스 머신에 만족스러워할 틈도 없이 유니티를 만질 일이 생겼다.

다행인 점은 얼마전부터 유니티에서 리눅스용 빌드를 지원하기 시작했다는 거다.

http://blogs.unity3d.com/kr/2015/08/26/unity-comes-to-linux-experimental-build-now-available/

게다가 아치리눅스 aur에 최신 빌드의 유니티 패키지가 올라와 있기까지 하니 설치는 식은 죽 먹기다.

소스에서 설치와 바이너리로 설치하는 두 버전의 패키지가 올라와 있다.

https://aur.archlinux.org/packages/unity-editor/

https://aur.archlinux.org/packages/unity-editor-bin/

자 이제 설치를 해보자.

yaourt -S unity-editor
혹은

yaourt -S unity-editor-bin

설치가 잘 되는듯하다가 다운로드가 자꾸 끊긴다.

스무 번 정도 시도하다가 안 되겠다 싶어서 따로 내려 받았다.

wget installer-url
혹은

curl -LO installer-url

64비트 우분투용 유니티 인스톨러:
http://files.unity3d.com/levi/unity-editor-5.2.2f1+20151018_amd64.deb

그 밖의 64비트 배포판용 유니티 인스톨러:
http://files.unity3d.com/levi/unity-editor-installer-5.2.2f1+20151018.sh

아래 링크를 따라가면 유니티 최신 빌드 정보가 있다.
http://forum.unity3d.com/threads/unity-on-linux-release-notes-and-known-issues.350256/

다운로드가 끝났다면,

yaourt -S unity-editor
설치를 하다가 다운로드에서 실패하길 기다린다.
실패하면 내려받은 인스톨러를 /tmp/yaourt-tmp-username/aur-unity-editor 폴더에 복사하고,
설치 다시시도를 누른다.
그럼 sha256sums으로 제대로 된 파일인지 검사를 하고 설치를 진행한다.

그리고 No space left on device라는 오류 메시지를 만났다.

유니티가 워낙 덩치가 크므로 기본 /tmp 용량으론 터무니없어서 그렇다.

https://www.reddit.com/r/archlinux/comments/2fj10b/no_space_left_on_device를 참조해서 해결책을 찾았다.

sudo systemctl mask tmp.mount && reboot

다행히 그 이후로 설치 과정에 어려운 점은 없었다.

unity-editor

커맨드를 실행하니 유니티창이 뜨고 로그인을 하라고 나온다.

이메일을 입력하려고 하는데 아무리 시도해도 키보드가 먹지 않는 거다.

혹시 지금 쓰는 Gnome3이 문제인가 싶어서 Xfce4에서도 시도해봤는데 여전히 키보드 입력이 되지 않는다.

unity-editor-bin과 unity-editor를 번갈아 설치하며 한참을 고생했다.

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

에도 마땅한 해결책은 보이지 않는다.

열심히 방법을 찾다 보니 미리 고생한 사람들이 여럿 보였다.

http://forum.unity3d.com/threads/unity-on-arch-manjaro-linux.350315/page-3#post-2271637

http://forum.unity3d.com/threads/unable-to-enter-text-after-clicking-somewhere.352213/

http://forum.unity3d.com/threads/first-start-logon-screen-no-keyboard-input.350396/

http://forum.unity3d.com/threads/cant-sign-in-on-unity-5-2-for-linux.369279/

리눅스를 쓰면 이런 점이 참 좋다. 전혀 모르는 사람들과 함께 고생하다 보면 리눅스 유저들에게 왠지 모를 친근감을 느끼게 된다.

하지만 맥을 쓴다면 그 시간에 커피 한잔 마시면서 여유를 만끽하겠지. OTL

Fluxbox에서 유니티에 로그인이 된다!

그리고 로그인 이후에는 원래 쓰던 DE에서도 잘 돌아간다.

아직 정식 버전이 아니라 그런지 종종 멈추긴 하지만 그래도 꽤 잘 돌아가는 편이다.



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

넥서스 5에 안드로이드 M 개발자 프리뷰 설치하기

한동안 elementalx 커널(http://elementalx.org/devices/nexus-5/)
과 cataclysm 롬(http://forum.xda-developers.com/google-nexus-5/orig-development/rom-cataclysm-nexus-5-t2518660)
으로 폰을 써 왔다.
순정 롬보다 더 좋은 점을 딱히 찾지 못했고, 종종 폰을 재부팅 해주지 않으면 느려지는 현상도 있었다.
그래서 롬을 새로 설치할까 고민하던차에 마침 android m preview버전의 소식을 듣고 폰을 갈아 엎었다.

설치 방법은 간단하다.
넥서스 5,6,9와 Nexus Player용 이미지를 다운 받는다.(http://developer.android.com/preview/download.html)
압축을 풀고 폰을 연결한다.
adb reboot bootloader 커맨드를 입력한다.
flash-all 커맨드를 입력하여 이미지를 설치한다.

리커버리는 TWRP(https://twrp.me/devices/lgnexus5.html)와 CWM(https://www.clockworkmod.com/rommanager/developers/hammerhead?name=Google%20Nexus%205)모두 설치가 되지만, 롬에서 바로 재부팅을 하면 무한부팅이 된다.
리커버리에서 필요한 이미지를 플래싱 했다면, fastboot모드로 들어가서 fastboot reboot 커맨드로 재부팅 해주자.

Android M에서는 Settings/Storage에서 Media device(mtp)나 Camera(PTP)모드 연결을 설정하지 못한다.
백업한 파일을 옮겨야 하는데 난감했다.
설정하는 방법은 아래와 같다.
  1. 설정(Settings)/폰 정보(About phone)에서 Build number를 터치하여 개발자 옵션을 활성화 한다.
  2. 개발자 옵션(Developer options)에서 USB debugging모드를 활성화한다.
  3. USB에 폰을 연결한다.
  4. 공지 창(notification bar)를 내린다.
  5. 실행중인 앱(ongoing) 에서 Touch for other USB options가 써있는 곳을 누른다.
  6. MTP로 설정한다.

그리고 Android M은 아직 루팅이 되지 않는다.
인터넷에 루팅 방법이라고 떠도는 방법들을 여럿 시도했으나, 무한 부팅(bootlooping)에 빠진다.
http://www.ibtimes.co.uk/how-root-nexus-6-5-9-android-m-developer-preview-build-mpz44q-1503606
http://wccftech.com/how-to-root-nexus-5-on-android-m/
혹 궁금하다면 위 링크를 보고 따라하면 무한부팅을 경험할 수 있다.
루팅이 되려면 Chainfire님이 SuperSU를 업데이트 해주시기를 기다려야 겠다.

Androd M을 새로 설치하니 런처의 앱 정렬이 가장 눈에 띄인다.
즐겨쓰던 야후의 Aviate처럼 알파벳 순 정렬이 되어 좋다.
최근 실행 앱 모두 종료 옵션이 없어서 좀 아쉽지만,
이대로라면 커스텀롬이나 런처 설치가 없어도 충분히 괜찮은 것 같다.
베터리도 예전 보다 더 오래가는 기분이다.(정확한 측정을 안해서 기분탓일 수도 있지만...)
그리고 반응속도도 전보다 빨라진 기분이다.(앱이 별로 안깔려서 그런지...)
롤리팝에서 돌아가던 앱은 Android M에서도 대체로 잘 돌아간다.
Push 알림에 이미지가 실려 나온다.
특정 시간에 알림을 받지 않는 설정이 기본 설정에 포함되어 있다.
넥서스 5에서 아래 오류 메시지와 함께 스크린샷이 안찍힌다.
Couldn't capture screenshot" can't take screenshot due to limited storage space, or it isn't allowed by the app or your organisation.
롤리팝에서 있던 버그라는데 이번에 처음 겪어본다.
롬을 새로 깔면 잘 된다고 하는데, 또 무슨 문제가 있을지 모르니 정식 버전이 나올 때 까지는 그대로 써야겠다.
Android M
아직 개발자용 프리뷰라 좀 불안정하지만, UI등 여러 측면에서 롤리팝 때보다 낫다.

참조

http://lifehacker.com/how-to-install-the-android-m-developer-preview-on-your-1707530107
http://support.wondershare.com/how-tos/why-can-t-i-find-usb-storage-mode-on-my-device.html
http://forum.xda-developers.com/apps/supersu



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

풍문으로만 듣던 Golang. 황무지에 꽃을 피우자.

벤치마크-'Go 언어. Golang.'

(출처 : http://www.techempower.com/benchmarks/#section=data-r9&hw=i7&test=json)

'Go가 이렇게 빠르다고?'
JSON serialization에서 특히 강세를 보이고, 다른 테스트에서도 상위권을 차지하는
이 벤치마크 결과를 본 후 Go 언어에 본격적인 관심을 두게 되었다.

웹을 주로 다루는 개발자의 관점에서 Go 언어의 첫 느낌.
그동안 많은 개발자의 사랑을 받은 자바, 파이썬, 루비, PHP 등엔 필요한 도구들이 이미 개발되어있다.
농사로 치자면 이런 언어들엔 트랙터와 콤바인은 물론, 이앙기와 탈곡기 등 필요한 도구가 다 잘 갖춰있다.
그런데 Go 언어로 개발하려니, 삽 한 자루로 굳은 땅을 개척해야 하는 느낌이었다.
와. 진짜.
잡초 조차 보기 힘든 황무지에 삽 한 자루 들고 발을 디딘 느낌이란...
참으로 막막하지만, 소로우가 살던 월든 호수를 동경하는 개발자로서 이런 황무지가 왠지 끌린다.
이 황무지 Go언어를 근 일 년 정도 접하며 느낀 점은 썩 괜찮다는 거다.
아직 많은 도구가 개발되진 않았지만 충분히 발전 가능성이 있는 언어라고 본다.

혹자는 시대를 역행하는 언어이고 후지니까 쓰지 말자고 한다.
초보자를 위한 언어지, 똑똑한 프로그래머를 위한 언어는 아니라고 한다.
그러나 Google, Spotify나 Docker같은 커다란 서비스에서 사용한다는 건,
그만큼 매력이 있다는 뜻이 아닐까?
만으로 여섯 살도 안된 언어가 이 정도면, 오 년 후에는 더 나은 모습을 기대할 만 하지 않을까?

사실 커뮤니티만 좀 더 발전해도 아주 흥하겠다.
루비나 파이썬과 비슷한 생산성을 가지고 성능은 몇 배 낫다면, 충분히 매력적이니까.
이 황무지에서도 잘 자라는 아몬드 나무를 심어볼 만하다.
그럼 봄이되면 꽃이 필테고, Go언어에도 봄 기운이 만연할 터이다.

아래에는 Go 언어에 아몬드 나무나 개나리, 진달래, 목련, 철쭉 등을 심어보고자 하는 개발자가 읽어볼 만한 거리를 정리하였다.


맛보기


패키지 정보


커뮤니티


파이썬 사용자라면?


더 읽어볼 거리


긍정적인 평가


비판



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

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

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!