조직구성원과 주주

주주는 기업에 돈을 투자하는 사람들이다.

조직 구성원들은 해당 기업에 인생을 투자하는 사람들이다.

따라서 경영인들이 더 잘 챙겨야 할 사람은 조직 구성원이다.

주주들도 시간을 투자하지 않느냐고 반문할 수 있다.

물론 맞다. 주주들은 투자하고 투자의 결과를 볼 때까지 기다려야 한다. 그럼에도 불구하고 조직구성원들에게 더 마음을 써야 하는 까닭은, 조직 구성원들이 조직을 위해 근로를 제공하는 동안 다른 일을 할 수 없다는 점에서 주주의 시간투자와는 개념이 다르기 때문이다.

조직구성원들을 챙기지 않으면 조직은 어떤 형태로든 그 결과에 대한 책임을 지게 된다.

LINE Works에서 Mailgun 활용하여 Gmail로 옮기면서 발생한 이슈

LINE Works가 이제 유료화를 보름 앞두고 있다.
그래서 G-Suite으로 이사할까 했지만, 어차피 유료고 업무용 메일도 아닌데 굳이 돈을 쓸 필요 있을까 싶어서 대안을 찾다가, Mailgun과 Gmail을 사용해서 개인 메일 세팅이 가능한 내용들을 검색하였다. LINE Works 때문에 벌써 고민하고 포스팅하신 분들이 있었다. 두 분께 이 자리를 빌어 감사드린다.

http://wequlo.blogspot.com/2017/04/mail-gun.html
http://recordingbetter.com/aws/2017/09/22/custom-domain-email-gmail-mailgun

위의 두 포스팅을 읽고 mailgun 세팅을 완료했다.

이제 테스트할 단계다. 그래서 Gmail에서 mailgun에 세팅한 개인 이메일 계정으로 메일을 보냈다.

“550 5.7.1 Relaying denied” 라는 메시지와 함께 메일이 들어오는 문제가 있었다.

이건 뭐지 싶었다. 일단 테스트를 3통 했는데, 모두 오류 메일이 함께 들어오는 것이다. 이건 뭔가 문제가 있는 거 같았다. 일시적이었을 거라 생각하며 마지막으로 한 통의 메일을 더 발송했는데, 메일이 아예 들어오지를 않는 것이다. 550 5.7.1의 오류 메일도 오지 않는 것이다. 직감적으로 Gmail에서 차단한 것이구나 싶었다.

그래서 해당 오류가 무슨 의미인지 찾아보기 시작했다. 아래 참고자료의 Ask leo의 내용을 읽어보면 쉽게 이해할 수 있다.

일단 이 문제가 발생한 기본적인 이유는 Gmail 발송 서버 -> 메일건(osg.kr) -> Gmail 수신 서버의 흐름으로 메일이 전달되는 구조에서 출발한다.

문제는 마지막으로 osg.kr(mailgun)에서 gmail로 relay하는 부분인데, gmail에서는 osg.kr에서 relaying하는 게 누구인지 신원 확인이 되지 않은 상황인 것이다. 신원이 확인되지 않은 메일에 대해서 Gmail 수신 서버는 차단하는 것이다. 그래서 “550 5.7.1 Relaying  denied” 메일을 세 번 받은 이후에는 더 이상 메일이 들어오지 않는 것이었다.

해결책은 Gmail 수신 서버에 osg.kr을 인증된 도메인으로 설정해 주면 된다.

1. https://postmaster.google.com/managedomains
2. 우측 하단의 + 표시를 누른다.
3. 인증할 도메인을 입력해 준다. 필자는 osg.kr을 사용하므로 osg.kr을 입력하였다.
4. NEXT 버튼을 누르면, DNS TXT에 설정할 값을 알려준다.
5. 해당 값을 인증할 도메인의 네임서버에 TXT 값으로 설정해 준다. 필자는 Vultr에서 네임서버를 사용하고 있으므로, vultr에서 ns 세팅을 하였다.
6. Verify 버튼을 누른다.

이제 Gmail에 들어가서 인증한 도메인의 메일로 메일을 발송해 본다. 아주 잘 들어오면 세팅이 끝난 것이다. 일단 필자는 이렇게 문제를 해결했다.

참고자료:
http://ask-leo.com/what_does_relaying_denied_mean.html
https://productforums.google.com/forum/#!topic/gmail/v8wVQIa0PTA

Python에서 용량이 큰 테이블의 insert, update 속도 문제

테이블 하나에 약 800만개의 레코드를 가진 테이블(약 1.2GB)을 만들고 분석할 기회가 생겼는데, 매일의 데이터 변경사항에 대해 추가하거나 업데이트를 해야 한다.

약 1,000개의 레코드를 업데이트하는데 25초 정도 걸렸다. 분명 뭔가 잘못됐다는 신호다. 초당 40개 정도의 업데이트밖에 되지 않았다.

해결책은 그리 복잡하지 않았다. 필자가 했던 적용법들은 다음과 같다.

1. select query를 사용하여 레코드 하나씩 1,000번씩 쿼리를 던져서 필요한 값들을 확인하던 것을 한 번의 쿼리로 작업 단위에 필요한 만큼 불러온 후, python에서 관련 값들을 확인하고 처리하도록 변경했다.

2. insert시 1,000개의 insert query를 실행하던 것을 다음과 같이 한 개의 insert query로 변경했다. 이 방법을 사용하는 경우 query문이 너무 길어지는 경우 실행되지 않을 수 있다. my.cnf에 관련 값을 얼마로 설정했느냐에 따라 달라지는 것으로 보이는데, key값이 지금은 기억나지 않는다. 추후에 확인해 보고 추가해 놓으려 한다.

insert into 테이블명 (필드1, 필드2, ...) values (값1a, 값2a, ...), (값1b, 값2b, ...), ..., (값na, 값 nb, ...)

3. update시 1,000개의 query를 실행하는 것은 동일하지만, where절에 키 두 개를 사용해서 update 하던 것을 primary key 하나만 사용하도록 변경하였다.

위의 3가지 방법을 모두 적용한 후 1,000개 레코드 처리에 25초 정도 걸리던 것은 평균 0.6초 이내로 처리시간이 단축되었다.

적용하기 전에는 Mysqld 프로세스의 CPU 점유율이 단일코어기준으로 100%이었는데, 변경 후에는 약6% 언저리에서 작동했다. 작업 환경은 다음과 같다. CPU는 인텔 G4400, 메모리 8G, SSD 128G, OS는 Windows 10, MariaDB 버전은 10.2를 사용하였다. 그리고 프로그래밍 언어는 Python3에서 MySQLdb를 사용하였다.

테이블 용량이 조금 크다고 해서 테이블을 여러개로 쪼개는 것이 우선이 아니라는 것을 이번에 배웠다. 특히 테이블 크기가 큰 경우에는 DB의 부하를 줄이는 방향으로 최적화할 필요가 있음을 느꼈다. 재미있는 경험이었으며, 기본적인 원칙이 얼마나 중요한지 다시금 생각해 보는 계기가 됐다.

mocha, jasmine 원하는 테스트만 실행/제외

Mocha에서 원하는 테스트만 실행하려 할 때는 .only를 사용하면 된다.

다음 예제의 경우 test 1만 실행된다.

describe('description', () => {
  it.only('test 1', () => {})
  it('test 2', () => {})
})

그리고, 다음의 경우에는 description 1의 test 1, 2만 실행된다.

describe.only('description 1', () => {
  it('test 1', () => {})
  it('test 2', () => {})
})

describe('description 2', () => {
 it('test 11', () => {})
 it('test 12', () => {})
})

그리고 제외하는 것은 .skip을 사용하면 된다. 작동되는 원리는 .only와 같다.

describe.skip(~)

it.skip(~)

Jasmine에서도 작동원리는 Mocha와 동일하다.

Jasmine에서는 focused의 의미로 f를 붙여서 원하는 테스트만 실행한다.

fdescribe(~)

fit(~)

그리고 제외하는 것은 exclude의 의미로 x를 붙여서 테스트를 제외시킨다.

xdescribe(~)

xit(~)

jasmine이 사용하기는 더 편해보이지만, mocha는 처음 보는 누구라도 쉽게 이해할 수 있도록 되어 있다.

<요약>
1. 원하는 테스트만 실행:
– mocha(describe.only, it.skip)
– jasmine(fdescribe, fit)
2. 원하는 테스트만 제외:
– mocha(describe.skip, it.skip)
– jasmine(xdescribe, xit)

Bitbucket 저장소와 Jenkins webhook 연동 – proxy

Jenkins와 Bitbucket Repository를 Webhook으로 연동했을 때의 문제는 webhook 조건을 pull request merged로 설정하면 브랜치 여부에 관계없이 webhook을 날린다는 것이다. 필자가 앞서 포스팅 한 글(https://blog.osg.kr/archives/80)에서 사용하는 방법도 마찬가지다.

안드로이드 프로젝트의 dev 브랜치가 pull request 됐을 때 개발용 앱을 빌드하고, master 브랜치에는 tag가 push 됐을 때 상용 앱을 빌드하도록 하고 싶다면? 어떻게 해야 할까? 이는 실제 필자가 서비스 개발에서 활용하고 있는 방법이다.

필자는 Proxy 서버를 Node.js로 간단히 구축하여 개발서버에서 구동하고 있다. Bitbucket에서는 webhook을 날리는 request body를 로그로 남겨준다. 로그에 기록된 body를 참조해서 해당 json을 파싱해서 활용하면 된다.

프록시 작동 원리는 다음과 같다. 개발용 앱 빌드의 경우 Bitbucket에서는 브랜치에 상관없이 pull request가 merge되면 webhook을 Node.js로 구축한 Proxy 서버에 보낸다. 프록시 서버는 body의 내용을 확인해서 dev 브랜치로 머지된 것인 경우에만 Jenkins 서버로 다시 Webhook을 걸어준다.

상용 앱 릴리즈 시에는 Bitbucket에 tag가 push되면 Proxy로 일단 webhook이 걸린다. 프록시 서버에서 body의 내용을 확인해서 master branch에 태깅됐을 경우에만 Jenkins로 webhook을 걸어준다.

단순히 도식화하면 아래와 같다.

Bitbucket Webhook > Node.js proxy > Jenkins task item

물론 Proxy 서버는 꼭 Node.js를 쓸 필요는 없다. 자신이 쓰기 편한 프레임워크를 사용하면 된다.

IntelliJ IDEA Preview 한글 깨짐

IntelliJ IDEA를 설치하면, 안드로이드 개발시 Layout xml의 Preview 창에 한글이 깨진다. 해결하기 위해서는 폰트를 재설정 해 주어야 한다.

필자는 금번에 Jetbrains의 Toolbox를 사용하여 IntelliJ IDEA를 설치하였다. 그래서 설치 경로는 다음과 같았다.

$HOME/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/172.4574.11/

폰트 설정 파일은 위의 경로 하위로 다음 경로에 있다.

plugins/android/lib/layoutlib/data/fonts/fonts.xml

노토 산스 CJK면 한글이 깨지지 않아야 할 것 같은데 깨지는 문제가 있다. 아래의 내용 중 NotoSansCJK-Regular.ttc를 나눔고딕으로 변경해 주면 된다.

<family lang="ko">
<font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
</family>

다음과 같이 변경하면 된다.

<family lang="ko">
<font weight="400" style="normal" index="1">NanumGothic.ttf</font>
</family>

IntelliJ IDEA 단축키 사용기

Jetbrains Night 서울에 참석한지 아직 일주일도 지나지 않았지만, 지난 한 주간 단축키 몇 개 더 쓰면서 들었던 생각과 금주에 학습하고 활용한 단축키를 몇 가지 소개하려 한다.

이전 포스팅에서도 언급했듯 한글97의 단축키는 대략 80% 이상을 외워서 사용했다. 물론 마우스 사용은 극도로 꺼렸는데, 그 이유는 문서 작업의 흐름이 끊기기 때문이었다. 단축키 5-6개로 작업 할 동안 마우스로는 한 두 가지 작업 밖에 못한다는 게 너무 답답해서, 늘 단축키를 습관처럼 사용했었다.

그러던 내가 IntelliJ IDEA를 사용하면서 활용하는 단축키가 30개도 안된다는 게 사실 이번 컨퍼런스에서 느낀 불편함이었다. 그래서 이번 행사에 참석한 후 intelliJ IDEA에서 최소한 일 평균 5번 이상 클릭이 반복된다 싶으면 단축키를 외워버리기로 마음을 먹었다.

이번 주에 사용하기 시작한 단축키가 몇 가지 있어서 소개하려 한다. 이미 아시는 분들도 많겠지만, 필자와 같이 그동안 단축키를 사용하지 않는 분들이 계실 수도 있으니 소개한다.

자주 사용하는 툴박스들의 단축키는 Linux에서는 Alt + 숫자키 그리고 맥에서는 Cmd + 숫자키이다. 특히 노트북을 사용할 때에는 화면이 비좁다. 때때로 툴박스를 접고 펴기 위해서 그동안은 마우스 클릭으로 토글해서 사용했는데, 단축키 한 번이면 마우스 움직이는 몇 초를 아낄 수 있다. ‘뭐 그깟 몇 초를 아낄려고 그렇게까지 하나’라고 생각할 수도 있는데, 그건 하루 이틀만 코딩하는 사람이라면 그렇게 말할 수 있을 것 같다. 뭐 똑똑하신 분들이야 시간이 좀 흘러도 작업하던 맥락을 잘 챙기시겠지만, 필자는 그리 똑똑한 편은 아니라 흐름이 끊기면 맥락을 다시 떠올리느라 고생한다. 뭐 그런 면에서 단축키는 분명 작업 중에 맥이 끊기지 않게 해 준다는 면에서 유용하다.

그리고 IDE 내의 터미널은 Alt + F12이다. 바로 해당 창을 열거나 닫을 때 해당 단축키들을 사용하니, 정말 편리하다.

기본으로 제공하지 않는 단축키들은 Settings(or Preferences)에서 직접 Keymap을 지정해 주면 된다. 안드로이드 개발 시에는 Android Monitor의 logcat을 활용할 때가 많은데, 기본으로는 단축키가 설정돼 있지 않아서 수동으로 설정해 주었다.

문자열 선택을 손쉽게 할 수 있는 단축키가 Mac에서는 Alt + up 또는 down 키를 사용해서 문자열 선택 범위를 넓히고 좁힐 수 있다. Ubuntu를 사용하면서 이 단축키를 찾았다. Ctrl + w 와 Ctrl + Shift + w로 각각 선택영역을 넓히고 줄일 수 있다.

마지막으로 단축키는 아니지만 가끔 문자열을 선택하고 따옴표나 쌍따옴표나 괄호로 묶어야 할 때가 있다. 문자열 시작점에 따옴표 하나 찍고 끝에 가서 따옴표 하나 더 찍기도 귀찮고 따옴표도 찍고 괄호도 쳐야하면 정말 귀찮기 짝이 없다. 그럴 땐 Settings(또는 Preferences)에서 Editor > General > Smart keys에서 Surround selection on typing quote or brace를 체크하고 적용한다. 그런 다음, 문자열 선택 후 따옴표나 괄호를 쳐보면 해당 문자열에 손쉽게 따옴표나 괄호 처리를 할 수 있다.

그동안 마우스로 클릭하면서 이걸 단축키로 할 수 없을까 싶었던 것들은 대체로 단축키가 있었다. 빠르게 단축키를 외우는 방법은 많이 사용해서 손에 익숙하게 하는 것보다 더 빠른 길은 딱히 없는 것 같다.

언젠가 기회가 되면 단축키 사용에 대해 정리를 한 번 해보고 싶다. 일단은 Jetbrains에서 제공하는 keymap 링크를 여기에 공유하며 글을 맺는다.

https://resources.jetbrains.com/storage/products/intellij-idea/docs/IntelliJIDEA_ReferenceCard.pdf

AWS EC2로 웹 서버 띄우기 전에 해야 할 일

필자는 AWS의 EC2 인스턴스를 제대로 활용해 볼 기회가 없었던, 그래서 AWS 초짜이다. EC2 인스턴스를 새로 생성해서 서비스해야 할 일이 생겨서 웹서버를 구축하다가 AWS 서비스의 구조를 잘 몰라서 잠시 고생을 했다. 웹서버를 띄웠는데 인스턴스와 IP는 어떻게 연결해 주어야 할 지, 도메인 세팅을 다 해 주었는데도 왜 접속이 되지 않았는지 고민하게 되었다.

결론은 AWS를 몰라서 생긴 이슈였다. 필자가 경험한 것을 바탕으로 AWS EC2 사용과정에서 꼭 필요한 과정들을 간단히 정리해 보았다. 혹여나 필자와 같은 처지에 있는 분들께 도움이 되길 바라는 마음으로 과정을 공유하고자 한다.

1. EC2 인스턴스를 생성한다.

2. ElasticIP를 추가한 후 생성한 인스턴스를 연결해 준다.

AWS의 인스턴스를 멈추고 다시 시작하면 새로운 내부 IP가 부여된다. 고정된 IP로 서비스하려면 엘라스틱 IP 서비스를 사용해야 한다.

3. 네임서버에 서비스하고자 하는 도메인에 대한 주소를 엘라스틱IP에서 할당받은 IP로 설정해 준다.

카페24나 도레지 등에서 네임서버를 설정할 수 있으면 굳이 라우트 53은 사용하지 않아도 된다.

4. 보안 그룹 페이지에 가서 서비스하고자 하는 포트를 열어준다.

기본적으로 EC2는 ssh 사용을 위해 22번 포트만 열어준다. 따라서 추가로 서비스를 제공하려면 해당하는 포트를 inbound에서 열어줘야 서비스가 가능하다.

JetBrains Night 서울에 다녀오고서..

어제 기다리고 기다리던 JetBrains의 행사에 다녀왔다. 행사의 주제는 IDE 팁, 생산성 향상을 위한 협업 툴 소개, 코틀린 소개, 레진코믹스에서 활용하고 있는 코틀린 현업 적용기, 그리고 질의응답 시간이었다.

일단 동시통역 덕분에 도움이 되기도 했지만, 개발 분야에서 사용되는 표현들을 해석하기보다는 그대로 말해주었다면 좀 더 매끄러웠을텐데 싶었던 부분도 일부 있었다. 하지만 나의 부족한 영어 실력은 통역의 도움을 안 받을 수 없었다. 어찌됐든 통역해 주신 분들께 이 자리를 빌어 감사의 인사를 전한다. 엄청난 집중력이 필요한 일인데, 그걸 해 내시다니 대단한 분들이라는 생각이다.

그 와중에 그냥 통역기 안 쓰고 행사에 참여하는 분들을 보며, 역시 가장 원활히 의사소통을 하려면 영어를 잘 하는 게 제일 좋겠구나 싶었다.

사설은 각설하고, 첫 세션은 IDE에 대한 팁을 알려주는 시간이었다. 추후 질의응답에서도 더 빨리 팁을 습득할 수 있는 방법이 없냐고 청중 속에서 질문이 있었는데, 역시 빠른 길은 없다. 그저 자주 사용해서 손에 익숙하게 만드는 방법 뿐인 거다. Hadi는 그냥 마우스 뽑고 키보드로만 IDE를 쓰라고 답해주어 청중에게 웃음을 주었다. 필자는 실제로 한글97을 사용할 때 마우스 사용 비율이 10%도 채 안 되었다. IDE도 그 정도로 꼭 쓰겠노라고 다짐했다.

별도의 유인물이 없어서, 일부 메모하기는 했지만, 너무 빠르게 진행이 되어서 도무지 뭘 봤는지 기억이 잘 나지 않는다. 역시 단축키는 그냥 외우고 직접 써보고 몸으로 편하구나를 느껴야 단축키를 쓴다. 예전에 생각했던 1일 1단축키 학습이라도 해야겠다.

생산성을 위한 협업 툴을 소개하는 시간에는 이슈 트래킹, 지속적 통합 등을 IDE와 연동해서 사용할 수 있음을 보여주었다. 대단하다 싶기는 한데, 사실 이미 다른 협업 툴을 쓰고 있다면 크게 필요가 있을까 싶었다. 필자는 회사에서 이슈 트래킹에는 gitlab을 CI에는 jenkins를 사용하고, 코드 리뷰에는 bitbucket을 활용하고 있다. 아직 협업 툴은 좀 더 지켜봐야 할 것 같다. 코드 리뷰 등에서 IDE의 코드 내용과 연동이 되면 좀 매력적일 것 같기는 하다.

그리고 가장 궁금했던 건 Kotlin 세션이었다. 재미있었던 것은 참가자들 중에 코틀린을 현업에 적용하고 있는 사람들은 많지 않았는데, 적용하고 싶어하는 사람들은 많았다는 것이다. 분명 Kotlin이 시장의 관심을 끄는 데에는 성공한 것이다. 물론 관심을 그렇게 끌기에 충분히 매력적이기 때문이리라 생각한다. 1.1 버전에 corputine과 typealias 등이 추가되었다고 한다. 자세한 건 역시 학습해야 할 것이다. 질의응답시간에 알게된 사실은 Jetbrains의 IDE도 코틀린으로 개발하고 있다는 것이었다. 자신들이 개발한 언어로 그들의 제품을 생산해 낸다는 것은 매력적이었다.

마지막으로 레진코믹스에서 Kotlin을 적용하고 있는 현업에서의 스토리를 만나보았다. 아무래도 우리말 세션이라 그런지 가장 이해하기 편했다. 가독성과 생산성이 가장 매력적인 지점으로 느껴졌다.

모든 시간을 통해서 공통적으로 느낀 건 기본기에 충실해야 한다는 거다. 겉멋만 들어가지고는 크게 도움이 되지 않는다는 것을 다시금 깨닫고 돌아왔다. 함수형 프로그래밍의 방법론들과 철학에 대해서도 다시금 고찰해 보기에 유익한 시간이었다.

관련영상 링크:

docker-compose 사용하기 – 2부. mariadb 추가설정 및 wordpress, nginx 설정

지난 번에 작성하던 docker-compose.yml 파일을 가져왔다.

version: '2.1'
services:
  mariadb:
    container_name: mydb
    image: mariadb:10.2.10
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_PW}
    volumes:
      - /Users/aaaa/con_volumes/mariadb/data:/var/lib/mysql
      - /Users/aaaa/con_volumes/mariadb/conf.d:/etc/mysql/conf.d

1부를 보셨던 분이라면 중요한 정보인 DB의 root 비밀번호를 MYSQL_PW라는 환경변수로 추출했던 것을 기억할 것이다.

환경변수로 추출할 부분이 더 있다. 바로 volumes에서 호스트의 경로 설정 부분이다. 컨테이너는 동일한 환경으로 구축해야 하지만, 로컬의 호스트는 사용자마다 다를 수 있다. 각자가 원하는 환경에서 도커를 구동하기 원할 것이다. 그래서 다음과 같이 환경 변수들을 추출하고, 설정파일 .env와 docker-compose.yml을 각각 다음과 같이 변경하였다.

MYSQL_PW=mypassword
MYSQL_DATA_PATH=/Users/aaaa/con_volumes/mariadb/data
MYSQL_CONFIG_PATH=/Users/aaaa/con_volumes/mariadb/conf.d
version: '2.1'
services:
  mariadb:
    container_name: mydb
    image: mariadb:10.2.10
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_PW}
    volumes:
      - ${MYSQL_DATA_PATH}:/var/lib/mysql
      - ${MYSQL_CONFIG_PATH}:/etc/mysql/conf.d

이제 어느 개발자의 머신에서든 서버에서든 각자의 입맛에 맞는 설정이 가능하다.

WordPress를 컨테이너로 띄울 것이다. 필자는 wordpress를 php 7.1으로 구동하는 fpm으로 띄울 것이며 도커 이미지 경량화를 위해 alpine 리눅스 이미지를 사용할 것이다. 관련 사항을 docker-compose.yml에 추가하려 한다. mariadb의 환경변수를 추출했던 것처럼 .env에 환경 변수는 별도로 설정한다.

# MYSQL
MYSQL_PW=mypassword
MYSQL_DATA_PATH=/Users/aaaa/con_volumes/mariadb/data
MYSQL_CONFIG_PATH=/Users/aaaa/con_volumes/mariadb/conf.d

# WORDPRESS
WP_DB_USER=root
WP_DB_PASSWORD=mypassword
WP_DB_NAME=my_wp_db
WP_DATA_PATH=/Users/aaaa/con_volumes/wordpress
version: '2.1'
services:
  mariadb:
    container_name: mydb
    image: mariadb:10.2.10
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_PW}
    volumes:
      - ${MYSQL_DATA_PATH}:/var/lib/mysql
      - ${MYSQL_CONFIG_PATH}:/etc/mysql/conf.d
  wordpress:
    container_name: wordpress
    image: wordpress:4.8.3-php7.1-fpm-alpine
    restart: always
    environment:
      - WORDPRESS_DB_HOST=mydb
      - WORDPRESS_DB_USER=${WP_DB_USER}
      - WORDPRESS_DB_PASSWORD=${WP_DB_PASSWORD}
      - WORDPRESS_DB_NAME=${WP_DB_NAME}
      - WORDPRESS_TABLE_PREFIX=wp_
    volumes:
      - ${WP_DATA_PATH}:/var/www/html

본 포스팅에서는 편의상 WP_DB_USER를 root로 설정해 주었다. 실제 상황에서는 maria db에 적절한 권한을 가진 사용자를 만들고 적어주면 되겠다.

이제 워드프레스 설정은 끝났다. 워드프레스 설정에 사용한 도커 이미지는 php-fpm으로 돌아가므로 nginx에서 proxy pass로 접근하게 할 것이다. nginx 컨테이너 설정도 추가로 해 준다.

# MYSQL
MYSQL_PW=mypassword
MYSQL_DATA_PATH=/Users/aaaa/con_volumes/mariadb/data
MYSQL_CONFIG_PATH=/Users/aaaa/con_volumes/mariadb/conf.d

# WORDPRESS
WP_DB_USER=root
WP_DB_PASSWORD=mypassword
WP_DB_NAME=my_wp_db
WP_WWW_PATH=/Users/aaaa/con_volumes/wordpress
version: '2.1'
services:
  mariadb:
    container_name: mydb
    image: mariadb:10.2.10
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_PW}
    volumes:
      - ${MYSQL_DATA_PATH}:/var/lib/mysql
      - ${MYSQL_CONFIG_PATH}:/etc/mysql/conf.d
  wordpress:
    container_name: mywp
    image: wordpress:4.8.3-php7.1-fpm-alpine
    restart: always
    environment:
      - WORDPRESS_DB_HOST=mydb
      - WORDPRESS_DB_USER=${WP_DB_USER}
      - WORDPRESS_DB_PASSWORD=${WP_DB_PASSWORD}
      - WORDPRESS_DB_NAME=${WP_DB_NAME}
      - WORDPRESS_TABLE_PREFIX=wp_
    volumes:
      - ${WP_WWW_PATH}:/var/www/html
  nginx:
    container_name: mynginx
    image: nginx:1.12.2-alpine
    restart: always
    ports:
      - 80:80
    volumes:
      - ${WP_WWW_PATH}:/var/www/html

일단 위와 같은 설정이면 컨테이너 3개가 모두 정상적으로 뜬다. http://localhost에 접속하면 welcome to nginx! 화면을 볼 수 있다.

이제 nginx에 워드프레스 php-fpm에 대한 proxy_pass를 설정해주면 된다.

그리고 컨테이너 간의 통신을 위해서는 networks 옵션을 사용하면 된다. 사실 지금까지 네트워크 옵션을 주지 않았지만, 자동으로 aaaa_default 라는 네트워크가 생성되어 해당 네트워크를 통해 통신하고 있었던 것이다. 필자는 my-net이라는 네트워크 이름을 지정해서 사용해 보도록 하겠다. 먼저 docker network create my-net 명령으로 네트워크를 생성한 후, 아래와 같이 .env와 compose 파일을 각각 설정한다.

# MYSQL
MYSQL_PW=mypassword
MYSQL_DATA_PATH=/Users/aaaa/con_volumes/mariadb/data
MYSQL_CONFIG_PATH=/Users/aaaa/con_volumes/mariadb/conf.d

# WORDPRESS
WP_DB_USER=root
WP_DB_PASSWORD=mypassword
WP_DB_NAME=my_wp_db
WP_WWW_PATH=/Users/aaaa/con_volumes/wordpress

# NGINX
NGINX_VHOSTS=/Users/aaaa/con_volumes/nginx/vhosts.conf

# NETWORK
MY_NETWORK=my-net
version: '2.1'

services:
  mariadb:
    container_name: mydb
    image: mariadb:10.2.10
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_PW}
    volumes:
      - ${MYSQL_DATA_PATH}:/var/lib/mysql
      - ${MYSQL_CONFIG_PATH}:/etc/mysql/conf.d
    networks:
      - mynet

  wordpress:
    container_name: mywp
    image: wordpress:4.8.3-php7.1-fpm-alpine
    restart: always
    environment:
      - WORDPRESS_DB_HOST=mydb
      - WORDPRESS_DB_USER=${WP_DB_USER}
      - WORDPRESS_DB_PASSWORD=${WP_DB_PASSWORD}
      - WORDPRESS_DB_NAME=${WP_DB_NAME}
      - WORDPRESS_TABLE_PREFIX=wp_
    volumes:
      - ${WP_WWW_PATH}:/var/www/html
    networks:
      - mynet

  nginx:
    container_name: mynginx
    image: nginx:1.12.2-alpine
    restart: always
    ports:
      - 80:8080
    volumes:
      - ${NGINX_VHOSTS}:/etc/nginx/conf.d/vhosts.conf
      - ${WP_WWW_PATH}:/var/www/html
    networks:
      - mynet

networks:
  mynet:
    external:
      name: ${MY_NETWORK}

이제 해당 컨테이너들은 my-net이라는 docker network를 공동으로 사용하게 된다. 같은 네트워크를 사용하는 컨테이너끼리는 대상 호스트명을 컨테이너 이름으로 사용할 수 있게 된다. 그리고 기본 엔직엑스 경로가 아닌 워드프레스를 내보낼 것이므로 내부 컨테이너 포트를 8080으로 변경해 주었다. 이제 엔직엑스 설정 파일 vhosts.conf를 살펴보겠다.

server {
    listen 8080;
    server_name localhost;

    root /var/www/html;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass mywp:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }
}

컨테이너 내부의 서버 포트는 8080으로 설정해 주었다. 그리고 fastcgi_pass는 docker-compose에서 컨테이너 이름으로 설정해 주었던 mywp를 호스트 이름으로 사용하고 있는 것을 볼 수 있다.

모든 설정이 다 되었다면, docker-compose로 컨테이너를 띄운다. 이제 웹 브라우저를 실행하고 localhost에 접속해 보면, 워드프레스 설정 화면을 만나볼 수 있다.

간단히 도커 이미지를 사용해서 워드프레스를 띄우는 작업을 함께 해 보았다. 참, 도커 이미지의 버전을 지정하지 않으면 최신 버전이 설치될 수 있으므로 동일한 환경 설정을 위해서 필자는 도커 이미지의 버전을 모두 지정해 보았다. 그리고 docker-compose에는 build 옵션을 사용하여 Dockerfile을 빌드할 수도 있다. 필자는 docker-compose를 적용한 후 자질구레한 중복 쉘 스크립트들을 제거할 수 있었고, 서버 재시작 시에도 안심하고 서버를 띄울 수 있게 되었다. 컨테이너를 효율적으로 관리할 수 있는 도구들이 또 있다고 한다. 좀 더 학습해 보아야겠다.

혹시 아직도 docker run으로 컨테이너를 띄우고 계신 분이 있다면, docker-compose 적용을 시도해 볼 것을 권한다. 이것으로 2부로 docker-compose 활용에 대한 포스팅을 마친다.