PHP 7.1 string -n

PHP 7.1부터 문자열에 -n을 사용해서 특정 문자를 다루거나 변경하는 게 가능하다.

$a = "100KB";
echo $a[-2].PHP_EOL;
$a[-2] = "M";
echo $a;

결과는 다음과 같다.

K
100MB

Dockerfile –build-arg option

도커 컨테이너를 띄울 때 volume을 설정해서 persistence를 잡아 줄 때, 컨테이너에 마운팅되는 방식이 머신별로 차이가 있는 것을 발견하였다.

필자는 php:7.1.10-fpm-alpine 이미지를 이용하여 컨테이너를 띄웠다.

볼륨을 마운트하면, 마운팅 된 디렉토리의 UID와 GID가 계속 1000으로 나오는 것이었다.

컨테이너에서 php-fpm을 띄우는 사용자는 www-data로 세팅해 놓았고, www-data 사용자의 UID와 GID는 둘 다 기본으로 82로 잡혀 있었다.

www-data 사용자로는 마운팅된 디렉토리에 쓰기 permission이 주어지지 않았으니 기록을 못하는 것이 당연하다.

그래서 찾아낸 것이 Dockerfile을 빌드할 때 주는 옵션이 있다는 것을 알게 되었다. 바로 “–build-arg 변수명=변수값”이다. 컨테이너 내의 사용자인 www-data의 UID를 Host에서 현재 docker를 사용하는 사용자의 UID로 바꾸면 된다.

docker build \
  --build-arg HOST_UID=$(id -u) \
  --build-arg HOST_GID=$(id -g)

위와 같이 UID와 GID를 설정하고 Dockerfile에는 아래와 같은 내용을 추가하였다.

ARG HOST_UID
ARG HOST_GID

RUN usermod -u ${HOST_UID} www-data
RUN groupmod -u ${HOST_GID} www-data

도커 이미지를 생성한 후 컨테이너의 www-data 사용자의 UID가 바뀐 것을 확인하였다.

이렇게 하면, 개발자마다 로그인하여 사용하는 PC의 UID가 다르더라도 각자의 환경에 맞게 적용이 가능하다.

필자는 개발용 머신으로 우분투 17.10을 사용 중인데, 별 문제 없이 잘 되었다. 하지만, MacOS에서는 Group 이름이 staff이며 GID는 20이라서 다음과 같이 충돌이 발생한다.

groupmod: GID '20' already exists

테스트 해 본 결과 Mac에서는 GID를 변경하지 않아도, Host의 파일의 권한이 Host의 UID와 GID로 유지된다. 하지만 Host가 리눅스인 경우 GID를 변경하지 않으면 컨테이너의 www-data 그룹의 기본 id인 82로 세팅되는 것을 확인하였다.

따라서 Mac에서는 빌드 시에 다음과 같이 GID 세팅을 빼 주면 된다.

docker build \
  --build-arg HOST_UID=$(id -u)

Dockerfile에서는 GID 변경 부분을 제외한다.

ARG HOST_UID

RUN usermod -u ${HOST_UID} www-data

작성하고 보니, 이 부분들도 쉘 스크립트를 작성하면 중복을 제거하고 하나의 파일로 구동이 가능할 것 같다. 이 부분은 독자의 몫으로 남겨놓겠다.

MacOS X 한영전환 -> Shift + Space

일단 아래의 파일을 찾는다.

~/Library/Preferences/com.apple.symbolichotkeys.plist

아래의 키에 해당하는 값을 찾는다.

Root > AppleSymbolicHotKeys > 61 > value > parameters > item 2

131,072라는 값으로 바꾸어 준 후, 재부팅하면 된다.

그냥 로그아웃하고 로그인 해 봤는데, 변경이 되지 않아서, 다시 설정하고 재부팅한 후 성공하였다. 사용하는 OS는 MacOS X High Sierra이다.

DOS를 운영체제로 쓸 때, 한글 1.x를 사용할 때부터 이미 shift + space로 한영 전환하는 것에 길들여져 있어서 지금도 그 버릇이 어딜 가지 않는구나 싶다.

출처: http://macnews.tistory.com/3736

Tutorial of automated Letsencrypt certificates with nginx

지난 포스팅에서는 certbot을 사용하여 gitlab의 인증서를 설치하는 법에 대해서 작성하였고, 자동으로 인증서를 재발행하도록 해 보아야겠다고 생각했었는데, 오늘은 엔진엑스에 인증서를 설정하고 자동으로 갱신되도록 하는 부분에 대해 작성해 보려 한다.

지난 포스팅 이후에 인증서 재발행을 간단히 실행해 보고, 문제가 될 수 있는 지점을 하나 발견하였다. –manual 옵션으로 인증서를 발행한 경우에는 certbot renew 명령으로 인증서 재발행이 불가능하다는 것이다.

기본적으로 certbot은 인증서를 생성하는 과정에서 해당 도메인에 접속가능한 것을 확인한 후에 인증서를 발행해 준다. 인증서를 수동으로 발행할 때에도 정해진 경로에 해당 파일을 생성하고 certbot에서 생성한 키를 파일 내용으로 적어서 저장한 후, 이후 과정을 진행했었다.

–manual을 쓰지 않아야 한다면, 명령줄 하나만으로도 가능하지 않을까라는 생각이 들었고, 어렵지 않게 파악한 명령줄은 다음과 같다.

certbot certonly \
  --webroot -w /var/www/blog.osg.kr \
  -d blog.osg.kr \
  --agree-tos

위에 입력한 옵션들에 대한 설명은 다음과 같다.

certonly(부명령어)는 인증서를 발행까지만 하고 자동 설치는 하지 않을 때 사용한다.
–webroot는 위에서 이야기한 인증 파일을 둘 경로를 지정할 때 사용하며, -w 옵션으로 해당 경로를 설정한다. 이 옵션을 사용할 때는 해당 경로를 미리 생성해 놓아야 한다.
-d는 SSL 인증서를 발행할 대상 도메인 이름을 지정할 때 사용한다.
–agree-tos는 이용약관에 동의한다는 것을 옵션으로 설정하는 것이다.

위와 같이 입력하고 실행하면 되는데, 뭔가 빠진 느낌이 들지 않는가. 그렇다. 위의 명령어를 실행하기 전에 먼저 해 주어야 할 것이 있다. 그건 바로 nginx에 .well-known 디렉토리에 대한 경로를 설정해 주어야 하는 것이다.

server {
    listen 80;
    server_name blog.osg.kr;

    ...
    
    location /.well-known/acme-challenge {
        root /var/www/blog.osg.kr/;
    }
}

파랗게 적은 부분은 .well-known/acme-challenge의 경로의 root를 설정해 주는 것이다. root로 설정했기 때문에 실제 파일의 경로는 아래와 같은 경로가 된다. 이제 nginx를 재시작 해 준다.

/var/www/blog.osg.kr/.well-known/acme-challenge/인증파일명

위에서 언급했던 certbot 명령줄을 입력해 주면, certbot이 위의 파일을 엑세스 한 후 해당 파일을 삭제하고, 최종적으로 인증서를 발행해준다. 인증서 발행 경로를 따로 지정하지 않았으므로 /etc/letsencrypt/live/blog.osg.org에 인증서가 발행되게 된다.

인증서 발행 후에는 nginx의 설정 파일에 아래와 같이 추가로 HTTPS 접속에 대한 설정을 해 주어야 한다. 인증서 적용에 필요한 부분만 적었기에 다른 부분들은 생략하였다.

server {
    listen 443 ssl;
    server_name blog.osg.kr;

    ...

    ssl_certificate /etc/letsencrypt/live/blog.osg.kr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/blog.osg.kr/privkey.pem;
}

SSL은 공개키 알고리즘을 사용하므로 ssl_certificate은 full chaining된 인증서의 경로를 적어주면 되고, ssl_certificate_key는 해당 인증서에 대한 개인키 경로를 적어주면 된다.

이제 엔진엑스를 재시작한 후, 자신의 도메인에 접속(필자의 경우 https://blog.osg.kr)하면 다음과 같이 자물쇠 표시가 된다.

이제 이 경로를 통해서 주고 받는 패킷들은 공개키 알고리즘을 사용해서 암/복호화가 이루어진다.

이제 앞서 이야기한 것처럼 인증서를 자동으로 재발행하는 게 가능하다.

certbot renew

라는 명령어 한 줄이면, 발행한 모든 인증서를 갱신해 준다. 하지만 발행한 지 일정 시간이 지나지 않으면 아직 발행할 때가 아니라며 인증서를 갱신해 주지 않는다.

이럴 때 강제로 인증서를 갱신하는 옵션이 있다.

certbot renew --force-renewal

–force-renewal 옵션을 추가로 적어주기만 하면, 인증서가 자동으로 갱신된다.

이제 해당 명령을 쉘스크립트로 생성하고, crontab에 원하는 주기에 한 번씩 실행되도록 등록해 주면 모든 준비가 끝난다. 인증서 갱신 때문에 인증서 설정을 새로한다든가 하지 않아도 된다. 단, 갱신된 인증서를 적용하려면 웹서버를 재시작해 주어야 한다. 웹서버 재시작까지 스크립트로 미리 준비해 둔다면, 별도로 웹서버를 재시작할 필요도 없을 것이다.

아참, 아직 crontab에 등록하는 것까지는 하지 않았다. 조만간 실행해 보고 잘 되면 추가로 포스팅 하도록 하겠다.

이제 인증서 발행과 설정 때문에 리소스를 과도하게 투입하지 않아도 된다. 사람이 손으로 일일이 설정하는 것들은 자동화해야 한다. 이렇게 자동화하면 아무리 많은 인증서도 자동으로 갱신되니 신경쓸 필요가 없다. 모든 설정이 끝났다면 인증서 갱신에 대한 걱정은 내려놓고, 집중해야 할 개발업무로 달려가면 된다.

2017 데이터 그랜드 컨퍼런스에 참석하며…

키노트와 비즈니스 키노트, 일련의 발표들을 들었다. 그리고 점심시간엔 부스에 전시된 제품들이나 연구결과들을 공유하는 자리에 가서 궁금한 것들을 물어보고 답변도 듣는 시간을 가졌다. 부스에서는 나도 모르게 “그러면 이 솔루션은 어디에 활용하는 건가요? 사용대상은 누구인가요?” 등의 질문이 툭 튀어나왔다. 산업 및 조직심리를 공부할 때 지도교수님께 지겹도록 들었던 질문을 내가 하고 있다니 세상에나!

연구결과는 실용성이나 시사점 또는 공익성이 있어야 하는 거다. 데이터 분석결과는 퍼즐조각들과 같아서, 하나의 이야기로 잘 연결하여 유의미한 그림을 제공하게 되면 분석결과의 가치가 빛을 발하게 된다. 그런데, 필자는 피같은 시간을 내서 갔는데, 어떤 명확한 그림에 대한 구경도 못한 채 그냥 분석해서 결과를 리뷰하는 수준으로 끝난 발표시간이 있었다. 빅데이터를 아무리 외치고 머신러닝을 한다고 해도, 산업이 크게 발전할 수 없는 데에는 다 그만한 이유가 있는 거라는 생각이 들었다.

예나 지금이나 변함없는 생각은 데이터 분석결과보다도 분석결과가 어떤 옷을 입느냐가 훨씬 더 중요하다는 것이다. 앞으로도 수많은 데이터들이 의미로 옷입고 세상에 자신을 드러냈으면 좋겠다. 조금 더 그런 자리에 있을 거라고 믿어본다. 나도 일조할 수 있으면 좋겠다고 생각하며 글을 맺는다.

JetBrains Night 서울

JetBrains에서 필자가 관심갖고 있는 영역을 모두 행사에서 다룬다고 한다.

첫째는 IDE Tips & Tricks 파트다. Webstorm에 이어 PhpStorm과 PyCharm까지 사용하다가 Android Studio를 사용해야 하는 상황까지 되어서, IDE를 여러개 쓸 수 없다는 생각에 IntelliJ IDEA까지 구매를 했음에도, 사실 아직도 많은 단축키를 제대로 활용하고 있지 못한 점이 영 마음에 걸린다. 과거에 한글97 워드프로세서의 단축키 80-90%를 암기해서 쓸 때만도 못한 수준이다. 뭐 개인적으로 단축키는 조금씩 암기하고 사용해 가고 있지만, 좀 더 능숙하게 연장을 다루고 싶은 마음은 늘 마음 한 구석에 있었다. 어떤 팁과 트릭이 공개될 지 궁금하다. 이참에 눈감고도 한글97을 썼던 느낌으로 IDE를 써야겠다는 강렬한 열망 같은 게 마음 속에서 꿈틀댄다.

둘째는 작업흐름이다. Trello, Gitlab, Jira, Slack 등을 사용했을 때의 잇점은 기록을 통해서 소통을 개선한다는 점이다. 문제를 빨리 발견할 수 있다는 점, 지식 전파가 빨리 이뤄진다는 점이 협업 도구 사용의 강점이라 할 수 있는데, JetBrains에서 제시하는 팀웨어 도구들이 어떤 지점에서 작업 흐름을 개선하고 생산성을 향상시키도록 고안됐을지 궁금하다.

셋째와 넷째는 최근 인기 상승 중인 Kotlin에 대한 내용이다. 안그래도 안드로이드 개발 및 iOS 개발을 모두 해야 할 때 리액트 네이티브나 자마린 같은 하이브리드 플랫폼을 선택해야 할 지, 안드로이드 앱은 Kotlin으로 iOS 앱은 Swift로 개발하는 게 좋을지 고민하는 중이었다. 이전에 Ionic과 React Native로 하이브리드 앱을 개발해 보았지만, 결국 네이티브 단에서 발생하는 이슈를 해결하려면 네티이브를 잘 알아야만 했다. 그렇지 않다보니 여차하면 삽질하기 일쑤였다. 그러던 와중에 현재는 java로 개발한 안드로이드 앱을 유지보수하고 있는데, 과연 코틀린이 가져올 생산성의 향상은 어느 정도일지, 그리고 코틀린의 특장점을 소개하는 자리가 될 것 같은데, 궁금하다.

행사 링크는 여기를 클릭!

docker –link option is deprecated

도커가 컨테이너를 띄울 때 내부 아이피를 사용하는데, 그 아이피가 고정되어 있지 않기 때문에, 컨테이너 간에 접근할 때 아이피를 사용하면 그 때 당시에는 되겠지만, 추후에 컨테이너를 다시 띄우면 IP 주소가 새로 할당되기 때문에 컨테이너 이름을 호스트 이름으로 사용해야 한다.

과거에는 –link 옵션을 사용해서 컨테이너를 서로 연결해 주었다. 이제는 docker network가 그 기능을 대신하고 있고, –link 옵션은 deprecated 상태이다. 언젠가 완전히 사라질 것이다.

네트워크를 설정하는 방법은 우선 도커 네트워크를 생성한다. 그 후에 컨테이너를 띄울 때 해당 네트워크를 사용하도록 설정해 주면 된다. 해당 네트워크를 사용하는 컨테이너에서 접근하고자 하는 대상 컨테이너 이름을 호스트 이름으로 사용할 수 있게 된다.

우선 도커 네트워크를 생성할 이름과 함께 아래와 같이 입력한다.

docker network create NETWORK-NAME

ls 명령어를 사용하여 도커 네트워크가 추가된 것을 확인한다.

docker network ls

이제는 특정 컨테이너를 실행할 때 사용할 네트워크를 지정해 준다. mysql과 php-fpm을 사용한다고 가정하고 아래와 같이 –network 옵션을 설정해 준다.

docker run ..... --name mysql --network NETWORK-NAME mysql:5.x.x
docker run ..... --name php --network NETWORK-NAME php:5.6-fpm

이제 호스트이름을 그냥 사용하면 된다. 위의 경우와 같이 컨테이너를 띄웠다면, 각 컨테이너의 이름인 mysql, php로 상호간에 접근할 수 있게 되었다.

그리고 이렇게 하면 해당 컨테이너의 해당 포트로 바로 접근 가능하므로 굳이 port를 publish 하면서 사용하지 않아도 된다.

만일 NGINX 컨테이너를 하나 더 띄워서 nginx.conf 에서 fastcgi를 설정하는 경우라면 php-fpm은 보통 9000번 포트를 사용하니 아래와 같이 설정해 주면 된다. 해당 서버 설정 구간에 다음과 같이 호스트명으로 잡아주면 된다.

fastcgi_pass php:9000;

 

참고자료: https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/

https://docs.docker.com/engine/userguide/networking/

Vultr 서비스 사용기

국내 호스팅으로 CAFE24를 아주 작게 사용해왔었다. 월 500원의 비용으로 매우 저렴하게 이용했었다. 워드프레스로 블로그를 시작하면서부터 SSL 인증서가 적용되지 않는 점이 마음에 걸렸다. Letsencrypt를 사용하여 발급받은 인증서는 CAFE24에 자동으로 업로드가 되지 않아서 고객센터를 통해서 요청해야 했고, CAFE24의 응대는 깔끔한 느낌이 아니었다. 그리고 결정적으로 SSL을 443 포트로 서비스 받을 수 없었다.

“클라우드 서비스 중에 좀 저렴하고 쓸만한 게 없을까? 혹시 지금쯤이면 좀 쓸만할 게 있을까?” 하는 마음으로 반신반의하며 구글링한 결과 해외 서비스로 VULTR가 있다는 것을 알게 되었다. 여러 서비스들이 있었지만, 가격대비 스펙이 매우 훌륭하여 선택하였다.

현재 VC2 서비스로 5불 짜리를 이용하고 있다. 가장 저렴한 요금제는 2.5불 짜리가 있는데, 1 CPU, SSD 20G, 메모리 512MB, 트래픽 500GB인데, 운영체제까지 입맛에 맞게 골라서 쓸 수 있다는 점에 확 넘어가 버렸다. 카페24의 최저 요금 서비스가 월 500원으로 SSD 200MB에 트래픽 400MB을 제공하는 것에 비하면 가성비는 Vultr의 압승이라는 생각이 들었다.

참고로 Windows OS는 월 16불의 추가비용을 내고 사용할 수 있다. 하지만, ISO 파일을 업로드 하면 추가 비용 없이 사용할 수 있다. 해당 ISO 파일은 VirtIO 세팅이 된 파일이 아니면 설치가 제대로 되지 않는다고 한다.

처음에는 가격부터 따져보았다. 어차피 큰 요금 차이가 아니니 써보고 로케이션이 맘에 안 들면 바꾸자고 생각했다.

월 2.5불의 최저 요금제를 지원하는 Location은 미국 마이애미와 뉴저지였다. ping을 쳐 보니 300~400ms 정도가 나왔다. 그래도 쓸만하지 않을까 하는 마음으로 일단 뉴저지 Location으로 신청해 보았다. 터미널을 사용하는데, 역시 반응속도 300~400ms는 답답한 감이 많았다. 싸게 쓰려 했으나, 지리적으로 우리나라에 사는 한 뉴저지는 불편하겠다고 판단했다.

그래서 고민을 다시 시작했다. 커피 한잔에 5~6천원 한다고 보면 그냥 5불짜리를 사용하는 것도 나쁘지 않겠다는 생각이 들었다.

5불짜리는 1 CPU, SSD 25G, 메모리 1GB, 트래픽 1TB 이었다. 이참에 한 달에 하루는 날을 정해서 음료고 뭐고 먹지 말자고 다짐하고, 그 돈으로 서버를 굴리자고 생각하고 다시 로케이션을 탐색했다.

가장 가까운 곳으로 도쿄와 싱가폴이 있었고, 그 다음으로 미국의 로스엔젤레스와 시애틀이 눈에 들어왔다. VULTR에서는 핑 테스트 할 수 있는 정보를 다음 경로에서 제공하고 있다.

https://www.vultr.com/faq/#downloadspeedtests

집에서는 KT 0.5G 인터넷을 사용중인데, ping을 날려보면 도쿄는 무슨 이유인지 반응속도가 30~100ms 에 이르기까지 널을 뛰는 모습을 보여주었고, 싱가폴은 90~100ms, 시애틀은 140~160 정도를 오가며 안정적인 모습을 보여주었다. 마지막으로 LA를 찍어보았는데, 134~136ms 정도를 꾸준히 안정적으로 유지하는 모습을 보여줬다.

도쿄는 가깝고 빠를 땐 빠르지만 안정적이지 못하다는 느낌을 받았다. 사실 일본은 자연 재해가 발생할 경우 그렇게 안전하지 않을 수도 있다는 생각이 들어서 선택지에서 제외했다. 싱가폴도 가깝기는 하지만, 동남아 쪽이 아닌이상 국제 서비스를 하기에는 반응속도 때문에 이용자들이 너무 느리다고 생각할 수 있겠다는 생각이 들었다.

LA를 선택하면 필자도 크게 불편을 느끼지 않을 것 같았고, 미국 전역에서 접속해도 느리다는 생각을 하지 않을 것 같았다. 뭐 아직 미국을 대상으로 무슨 서비스를 할 생각은 없지만, 마음은 늘 원대하게 품어보는 것이니ㅎㅎ

결국 LA에 VC2 인스턴스를 생성하였으며, 필자는 도커 기반으로 서버를 운영할 것이라 운영체제는 CoreOS를 선택해서 설치하였다.

스냅샷 기능을 사용하면 현재의 상태를 보존할 수 있다. 다른 인스턴스로 이관할 필요가 있을 때 사용하면 된다. 고스트 이미지 떠 놓은 느낌이랄까. 일단 오늘 워드프레스를 이전한 기념으로 VULTR 사용기를 작성해 보았다.

참, VULTR은 회원에게 보상해 주는 제도가 있다. 회원의 소개로 가입해서 결제하면, 회원에게 보상을 해 준다. 보상 비용은 Paypal 계좌로 받을 수도 있고, 서버 운영비 계좌로 받을 수도 있다. 아래와 같은 배너도 제공해 준다. 원하는 배너를 선택해서 활용하면 되겠다.

그럼 VULTR 서비스에 대해 자세히 알아보려면, 클릭↓ 꾹~*

phinx 실행시 timezone 문제 발생하는 경우

사실 phinx의 문제라기보다는 php 환경변수로 timezone이 설정되지 않아서 발생하는 경고 메시지이다.

필자는 phinx를 사용하여 마이그레이션하려할 때 아래와 같은 경고 메시지를 받았다.

Warning: date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone.

설명에도 나와있듯 php.ini에 date.timezone 값을 설정해 주거나, 관련 코드 실행시에 date_default_timezone_set()을 사용하면 된다.

우리나라의 경우에는 ‘Asia/Seoul’을 다음과 같이 적어주면 된다.

date.timezone = Asia/Seoul

date_default_timezone_set(‘Asia/Seoul’);

필자는 서버 환경 설정과 관계 없이 코드를 통해 동일한 결과를 만들어 내기 위해 phinx.php에 코드로 작성하여 문제를 해결하였다.

phinx db migration tool setting

phinx.yml 에서

host를 localhost로 할 때엔 unix_socket을 정해줘야 한다.

host가 localhost인데 unix_socket이 설정되어 있지 않으면, 다음과 같은 에러를 보게 된다.

[InvalidArgumentException]
There was a problem connecting to the database: SQLSTATE[HY000] [2002] No such file or directory

unix_socket을 사용하지 않으려면 host를 127.0.0.1로 하면 된다.

참고자료: https://stackoverflow.com/questions/22188026/sqlstatehy000-2002-no-such-file-or-directory/25782795#25782795