• react-router v4와 함께 페이지 라우팅 하기

    최근 글쓰기가 뜸했다. 인정한다. 여러모로 바빴다. 웹 애플리케이션 하나도 만들고 있고, 결과는 암담하지만 면접도 한번 보고 왔다. 슬슬 글 하나 정도는 써주지 않으면 영원히 쓰지 않을 것 같아 부랴부랴 올린다. 없겠지만 혹시라도 기다렸던 분들 있으면 미안하다.

    왜 react-router v4 인가?


    react-router로 페이지 라우팅 하는 법을 다루려면 그냥 react-router 라고만 적지, 왜 버전명이 같이 언급됬는지 궁금하신 분들 계실 거다. 결론부터 말하면 react-router v4와 그 이전 버전의 사용법이 많이 달라졌기 때문이다. 다시 말해, 잘 사용하던 코드를 v4에 그대로 끼얹으면 작동을 안 한다는 소리다.

    말만 들어도 고통스럽다. 벌써부터 온몸이 아파온다. 그래도 이것이 지금의 JS다. 15년 전 홈페이지에 눈내리기 효과 넣어주던 ‘매크로’가, 하루가 다르게 새로운 기술이 나오고 파이썬, 루비 등과 어깨를 나란히 하는 활발한 스크립트 언어가 되었다. 몸 좀 아파도 끝없이 성장해나가는 JS를 위해 우리 좀 참아주자.

    알맹이

    아래는 기존에 사용되던 알맹이 코드이다.

    <Router history={browserHistory}>
          <Header />
            <Route path="/" component={Main}>
                <IndexRoute component={Main}/>
                <Route path="auth" component={Auth}/>
            </Route>
        </Router>
    

    나름 직관적으로 적혀 있어 React를 조금 만져보신 분들이라면 이해에 큰 어려움이 없을 것이라 생각된다. 처음 홈페이지를 접속했을 때(/) Main 컴포넌트가 뜨고, /auth 주소로 접속하면 Auth 컴포넌트가 뜨는 코드다. (browserHistory는 웹페이지에서 뒤로가기를 눌렀을 때도 전체가 새로고침 되지 않도록 도와주는 기능, IndexRoute는 웹페이지의 첫 화면을 정의해주는 기능이다.)

    문제는 아까 말했듯 이렇게 열심히 작성한 코드가 최신 v4 버전에서는 깡통이 되어버린다는 것이다. 깡통이라는 표현이 절대 빈말이 아니다. v4 버전에 적용해보면 정말 아무것도 랜더링하지 못한다. 하얀 화면만 끝없이 펼쳐질 뿐이다. 숙련자들도 골치 아픈 문제지만, 특히 처음 React를 접한 분들에게는 더 치명적이다. 나는 분명 가이드 글에 맞추어 코드를 짰는데 아무것도 나오지 않는다. 으악.

    이 글을 찾아오신 분들도 대부분 위같은 문제에 시달리고 있을 것이다. 그럼 더 이상 뜸들이지 않고, 위 코드를 v4에서 작동될 수 있는 코드로 변환해 보겠다.

    <Router>
        <div>
          <Header />
          <Route path="/" exact component={Main} />
          <Route path="/auth" component={Auth} />
        </div>
      </Router>
    

    짜잔. 비슷하면서도 조금 더 간결해지지 않았는가. 이전 버전에서 사용했던 페이지 전체 새로고침 방지 목적의 browserHistory는 더 이상 사용하지 않아도 되고 (역할이 많이 바뀐 것 같다. 자세한 것은 나중에 추가할 예정), IndexRoute 대신 exact를 사용해 첫 페이지를 정의해줬다.

    마치며

    react-router는 위 같은 간단한 페이지 라우팅을 넘어 훨씬 더 복잡하고 많은 일을 할 수 있지만, 이 글의 목적은 그 ‘간단한 페이지 라우팅’ 이였다. 가장 기본이 되는 기능이고, 또 없어서는 안될 기능이다. 지금까지 골머리 썩었던 분들이 도움을 받아갈 수 있었으면 좋겠다.

  • 야근과 업무 효율성에 관하여


    우리는 알게 모르게 오래 일하는 것을 미덕으로, 휴식을 죄악으로 생각하는 문화를 가지고 있다. 누구가 잠을 줄여 높은 점수를 맞았다는 이야기는 학창 시절에 꼭 들어보는 이야기다. 우리는 자라오면서 그렇게 교육받았고, 그렇게 생각하는 것이 몸에 배어있다. 그리고 이런 악습은 잠을 줄여 공부하던 학생이 성인이 되었다 하더라도 없어지지 않는다. 여전히 공무원 시험 등을 위해 휴식과 잠 대신 책을 잡거나, 취직을 하더라도 많은 경우 상습적인 야근 요구를 받는다. 결론을 한 마디로 말하겠다. 야근과 업무 효율성은 전혀 비례하지 않는다.

    사람을 포함한 동물이 휴식을 취하고 잠을 자는 것은 다 이유가 있다. 누구나 아무리 편하게 지낸다고 해도 쌓이는 스트레스를 해소하고, 일일 처리 한계에 다다른 뇌를 슬립 모드로 넘겨 자료를 정리하고 찌꺼기를 걸러내야 한다. 그런데 이런 당연한 과정을 무시한 채, 단순히 오래 앉아 있기 = 오래 작업하기 로 생각하는 일부 몰지각한 고용주들이 끊임없이 만행을 저지르고 있다.

    문제는 이러한 일이 깊은 집중력과 정신력이 필요한 IT 분야에서까지 그대로 벌어지고 있다는 뜻이다. 아니, IT 분야의 야근은 적어도 대한민국에서는 서로 떨어지지 않는 짝꿍 키워드다. 인간이 하루에 집중할 수 있는 시간은 대충 2~3시간 정도로 알려져 있다. 하루 정상근무 8시간을 한다고 해도 2~3시간 정도만 집중해서 작업할 수 있으면 그날 몫은 다 했다는 뜻이 된다. 나머지 시간은 수다떨고 멍때리고 간식 먹는 시간으로 쑥쑥 지나간다.

    ‘깊은 집중력과 정신력이 필요한 일’이 만드는 결과물이 과연 양으로 따질 수 있는 것인가? 아니다. 어디까지나 질이 가장 중요하다. 똥덩어리 코드 100줄보다 깔끔하게 동작하는 코드 5줄이 결국 훨씬 이득이다. 필자가 이전에 읽은 한 글에서는 ‘코드를 짜기 위한 야근’이 마치 ‘따뜻한 얼음’과 같이 모순되는 말이라고 했다. 정상 업무 시간동안 단순 반복 업무만 계속하라고 해도 힘들 것인데, 야근까지 하며 정신력을 소모하는 일이 절대 잘 돌아갈리가 없다.

    그렇다고 당장 야근에 반대하며 파업에 들어가라는 것은 아니다. 우리는 힘없는 소시민이라 잘못하면 당장 생계가 위험해질 수도 있으니 말이다. 이 글의 요지는 야근이라는 행위 자체의 업무적인/개인적인 이득이 전-혀 없는 것을 다시 한번 자각하고 어떻게 하면 조금 더 실용적인 방향으로 업무 스타일을 바꿀 수 있을지 고용인과 피고용인 가리지 않고 고민해보는 시간을 가져보자는 것이다. 물론 그것이 가능했으면 진작 이 지경까지 오지 않았겠지만, 가만히 손을 놓고 있으면 영원히 바뀌는 것은 없다. 약간의 추진제 역할만 해준다고 해도 충분하다. 누군가는 당연한 것이라고 생각하지 않고 있어야 더 나은 방향으로 나아갈 수 있다.

  • RESTful한 머릿속 만들기

    어디서 한번쯤 들어보지 않았는가. “RESTful 한 웹서비스를 만들어야 한다.”, “우리 웹 애플리케이션도 REST를 고려하고 만들어졌나요?” 머릿속이 복잡해져 다시 REST가 무엇이냐 물어보면 우물쭈물 명확한 대답은 안 나온다. 자기들도 확실히 모르는 개념을 웹 서비스에 적용하라고?


    진정하자. 지금부터 무엇인지 알아갈 것이다. 복잡할 것 없이 REST는 일종의 웹 서비스 설계 기준일 뿐이다. 가이드라인이 존재하고, 그것을 준수해 웹 애플리케이션을 만들었으면 그게 RESTful한 웹 서비스가 되는 거다!

    쓰면 어디에 좋나요?

    REST 아키텍처는 이미 전 세계에서 사실상 표준으로 자리잡았다. 다시 말해, 어떤 OS/브라우저를 사용하던 모두 커버할 수 있는 범용성이 보장된다는 소리다. 십수년 전에는 IE만 지원하면 장땡이였지만, 지금은 메이저 PC 브라우저도 훨씬 많고 심지어 모바일 환경도 존재한다. 이 많고 많은 환경을 일일히 따로 설계해 지원할 것인가? 별로 좋은 생각은 아닌 것 같다. 주민등록 주소지를 회사 사무실로 새로 신고해야 할 수도 있다.

    REST 가이드라인을 따르면 위와 같은 참사를 피할 수 있다. 내 시스템 디자인을 명확하게 확립할 수 있게 해주고, 여러 기기에서 모두 사용할 수 있는 범용성도 보장할 수 있다. 나머지 이점들은 아래 특징들과 함께 살펴보도록 하자.

    특징

    위키피디아의 REST 문서를 살펴보면 이것저것 외계어가 적혀 있다. 물론 전부 알아두면 좋지만, 당장 끌어올 뇌 리소스가 부족한 분들은 아래 핵심 개념 2가지만 살펴봐도 충분하다.

    URI는 직관적, 그리고 의미 중복 없이 정보(자원)을 가르켜야 하고, 모든 상호작용은 HTTP 메소드를 사용해야 한다.

    먼저, 맨 앞의 ‘URI‘는 ‘URL’의 오타가 아니다. URI는 URL을 포함하는 상위 개념 정도로 보면 된다. 기존 우리가 알고 있던 URL의 역할처럼, 온라인 상의 무언가를 가르키는 주소다. 예를 들어, https://www.google.com 은 URI이면서 URL이다. 아직까지는 이해가 잘 안될 것인데, 다른 예시를 하나 더 가져와 보겠다. https://www.google.co.kr/search?q=uri 주소의 /search 까지가 URL, 그리고 ?q=uri(쿼리스트링) 부분은 ‘URN‘이다. 외계어를 하나 더 꺼내와서 미안하다. URN도 마찬가지로 URI의 하위 개념 중 하나이다. 그리고 방금 예시로 보여준 주소처럼, URL + URN = URI가 되는 것이다. 조금 빙 돌아온 느낌이 없잖아 있는데, 대충 URI가 무엇인지 느낌이라도 알았다면 성공한 거다.

    이제 뒷부분을 보자. ‘모든 상호작용은 HTTP 메소드를 사용해야 한다’ 라고 했는데, 여기서 ‘HTTP 메소드‘는 어쩌면 익숙할 수도 있는 GET, POST, DELETE 등을 뜻한다. 여기서 일일히 메소드들의 종류를 전부 나열하지는 않겠다. 대신 위 링크에 들어가 자세한 메소드, HTTP 응답 코드 등을 살펴보길 바란다.

    아래 RESTful한 HTTP 메소드 예시는 이곳을 참고했습니다. 작성자님 감사합니다.

    아래는 바람직하지 않은 글 목록에서 5번 글을 받아오는 GET 메소드 예시이다.

    GET /posts/show/5
    

    영 좋지 않다. HTTP 메소드 GET은 이미 정보 검색을 서버에 요청하는 기능을 담고 있는데, 또 URI에 show라는 동사를 넣어 ‘보여준다’ 라는 의미를 중복시킬 이유는 없다. 위 URI는 아래처럼 수정할 수 있다.

    GET /posts/5
    

    깔끔하고 좋지 않는가? 직관적이고 의미 중복도 없어졌다.

    마치며

    “엥? 이게 끝이야?” 라고 물어볼 수도 있을 거다. 예. 끝입니다. 이 글의 취지는 REST 라는 개념을 이해하는 것이였지, 어떻게 당장 웹 애플리케이션을 RESTful하게 짤 수 있는지에 대한 글은 아니다. 어쩌면 나중에 다룰 지도 모르겠다. 그때가 되면 이곳에 링크를 달아 두겠다. 필자처럼 웹에 무한한 매력을 느껴 새로 홀려버린 분들을 위한 글이였다.

  • Docker Swarm으로 고래엮기

    Docker Swarm?


    서버 오케스트레이션 이라는 애매모호한 용어가 있다. 혹시 백엔드 쪽에 관심이 있는 분이라면 인터넷 어디선가 한번쯤 들어봤을 수도 있겠다. 이게 쓰는 사람에 따라 의미가 조금씩 달라지는 용어라 위에 ‘애매모호’ 라고 표현을 헀는데, 기본적으로 IT 인프라의 자동화 라는 뜻을 가지고 있다. 오늘 다룰 Docker Swarm이 바로 “IT 인프라의 자동화”를 할 수 있게 도와주는 오케스트레이션 도구다.

    당연히 Docker 컨테이너를 기반으로 오케스트레이션을 구현해주는 도구가 이것만 있는 것은 아니다. 다만, Docker Swarm은 무려 Docker의 내장 기능이라 기존에 사용하던 Docker의 다른 기능들, 그리고 명령어들과 눈물나게 잘 어우러지는 말 그대로의 오케스트라를 보여 주는 덕에 뒤도 안보고 선택하게 되었다. 그런데 이런 내장 기능들이 다 그러하듯, 정말 깔끔하게 필요한 기능들 이상은 제공하지 않는다는 단점 아닌 단점은 존재한다. 혹시 Docker Swarm 이상의 기능이 필요한 분들은 아쉽지만 뒤로가기를 눌러 구글로 돌아가길 바란다.

    백문이 불어일견이라고, 아래 이미지를 보자. 기본이 되는 Docker Swarm 인프라의 구성도다.


    아마 한눈에 어느정도 이해가 갈 것이다. 위의 Swarm Manager가 아래 Docker 데몬이 돌아가는 Worker 들을 중앙 관제하는 방식으로 구성되어 있는데, 관리자는 Swarm Manager에 터미널이나 Docker Compose 등으로 명령을 내려 아래 서버들까지 한번에 컨트롤 할 수 있다. 이러한 Master가 Slave들을 조련하는 중앙 관제 방식은 비단 Docker Swarm 뿐만 아니라 대부분의 오케스트레이션화가 진행된 인프라에 공통적으로 쓰이는 ‘정석’이니 지금 익숙해지면 나중에 편할 것이다.

    설치하기

    아래 과정을 진행하며 이 포스트를 많이 참고했다. 개인적으로 한국어로 작성된 Docker Swarm 관련 포스트 중 가장 잘 쓰여진 글이라 생각한다. 작성자님 감사합니다.

    위에 올려둔 인프라 구성도 (스크린샷)를 그대로 따라갈 것인데, Docker Swarm이 설치될 테스트 환경은 Vagrant라는 VM 자동화 도구를 사용하여 구축하겠다. 필자의 GitHub에 모든 것이 준비된 Vagrant 패키지를 올려뒀으니, 다운로드받아 실행만 하시면 된다. 위 링크를 달아둔 포스트의 작성자님이 미리 만들어둔 것을 가져와 약간 수정한 것이다. 지금 사용한 Vagrant는 곧 따로 포스트를 작성할 예정이다. 완성되면 이곳에 연결해 두겠다.

    구성도처럼 우리 Docker Swarm 클러스터의 Manager는 core-01가 될 것이다. vagrant ssh core-01 명령어로 core-01과 터미널 연결을 한 후, 아래 명령을 실행하여 Docker Swarm을 시작해 보자.

    docker swarm init --advertise-addr 172.17.8.101
    

    자, 순식간에 Docker Swarm 클러스터가 시작되었다. 아마 아래와 유사한 출력값이 나왔을 거다.

    Swarm initialized: current node (y01bcscl168g9npunryt0fv5w) is now a manager.
    
    To add a worker to this swarm, run the following command:
    
        docker swarm join \
        --token SWMTKN-1-2hkjkxqnqt5dmizyr8lr59elc3dsuwoc5c2kgzbzont2pilcua-auleg4b3rtj3hkgudm4gqhj2o \
        172.17.8.101:2377
    
    To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
    

    Docker Swarm이 시작되었고 이 노드(core-01)이 Manager라는 사실, 그리고 Worker들은 어떻게 추가해야 하는지 설명해 주고 있다. 너무 순조롭고 친절해서 눈물이 나올 지경이다. 클러스터링이 이렇게 쉬운 일이 될줄 누가 알았겠는가.

    눈물은 조금 이따 마저 흘리도록 하고, 일단 시키는대로 Worker 노드들도 추가해 보자. 나머지 노드 (core-02, core-03, core-04) 들에 접속하여 위 docker swarm join 명령어를 복사 & 붙혀넣기 해보자. This node joined a swarm as a worker. 이라는 짧고 강력하게 정상적으로 Worker가 되었다는 사실을 알려준다.

    이제 core-01로 돌아가 docker node ls 명령어를 입력해보자. 이 Swarm 클러스터에 어떤 노드들이 있는지 한눈에 확인할 수 있다. 방금 추가한 Worker 노드들이 정상적으로 표시된다면 제대로 진행한 것이다.

    아직 할 일이 하나 남았다. 우리가 core-01로 돌아온 것은 클러스터의 상태를 확인하려는 목적도 있었지만, 위의 구성도에 보이는 것처럼 Manage 노드를 하나 더 추가하려 온 것이다. 혹시 처음 docker swarm init 명령어로 클러스터를 시작했을 때, 출력값 맨 아래에 Manager를 추가하는 법도 알려줬던 것을 눈채챘을지 모르겠다. docker swarm join-token manager 명령어를 입력하면 Worker 추가 명령어와 마찬가지로 아래처럼 인증 토크값과 함께 Manager 추가 명령어를 알려준다.

    To add a manager to this swarm, run the following command:
    
        docker swarm join \
        --token SWMTKN-1-2hkjkxqnqt5dmizyr8lr59elc3dsuwoc5c2kgzbzont2pilcua-7g5mef5gjj8zlr6kesyzqk83i \
        172.17.8.101:2377
    
    

    이걸 복사한 후, core-05로 접속하자.

    core-05에서 위 명령어를 붙혀넣기만 하면 “This node joined a swarm as a manager.” 라는 메시지와 함께 Manager 추가도 끝난다. 축하한다. 3대의 Worker 노드, 그리고 2대의 Manager 노드로 구성된 고가용 클러스터가 완성되었다. 이제 아래로 넘어가 이 덕심을 자극하는 클러스터로 무언가 돌려 보도록 하자.

    애플리케이션 올려보기

    Docker Hub에서 웹 애플리케이션 (Flask 데모)을 하나 끌어와 클러스터에 올려보자. Manager 노드에 접속하여 아래 명령어를 쳐보자. Docker Hub에 올라가 있는 p0bailey/docker-flask을 끌어와 80:80 포트로 실행하는 명령어이다.

    docker service create --name flaskontesting \ # flaskontesting에는 원하는 이름 입력
      -p 80:80 \ # 연결할 포트
      p0bailey/docker-flask # Docker 이미지의 이름
    

    별다른 경고 없이 무언가 알 수 없는 값 (필자의 경우 3pyk3b8bo9t01r8ct2fhtregk)이 출력되었다면 정상적으로 서비스가 실행되고 있다는 뜻이다. 방금 출력된 값은 우리가 이번에 실행한 서비스의 ID값이다. docker service ls 명령어로 현재 실행되고 있는 서비스를 확인할 수 있다.

    조금 더 자세한 정보를 원한다면 docker service ps 서비스이름 명령어를 입력해보자. 필자의 경우 아래같은 출력값이 나왔다.

    ID            NAME              IMAGE                         NODE     DESIRED STATE  CURRENT STATE           ERROR  PORTS
    1iqh5ti6ditt  flaskontesting.1  p0bailey/docker-flask:latest  core-05  Running        Running 10 minutes ago       
    

    현재 서비스의 상태, 서비스의 ID값, 이름, 사용하고 있는 이미지, 그리고 서비스가 돌아가고 있는 Swarm 노드 등의 정보가 자세히 출력된다. 그런데 여기서 궁금한 점이 생긴다. 왜 Manager 노드인 core-05 에서 서비스가 돌아가고 있는 것으로 나오고, 또 접속은 어떻게 해야 하는 건가? 정말 core-05의 IP주소를 일일히 치고 들어가야 하는 걸까?

    필자도 처음에는 어버버 했었다. 지금부터 하나하나 설명할 것이니 너무 어려워 하지 마라. 먼저, 기본적으로 Manager는 단순히 Worker를 관리하는 매니저의 역할만 하는 것이 아니라, 본인이 일도 같이 하는 ‘Manager + Worker’의 상태이다. 따라서 설령 내 Swarm 클러스터에 Worker 노드가 하나도 없다고 해도 정상적으로 애플리케이션을 실행할 수 있다. 물론 Manager 노드가 매니저의 일만 하도록 지시할 수도 있는데, 이 글 을 참고해 보길 바란다. Manager 노드가 Worker의 일도 같이 한다는 것과, 추가로 Manager 노드에게 매니저의 일만 하도록 설정하는 법이 잘 설명되어 있다.

    두번째로, 접속할 때 core-05의 IP를 일일히 확인하고 입력할 필요는 전혀 없다. Docker Swarm은 기본적으로 Ingress라는 오버레이 메시 네트워크를 사용한다. 말이 어려운데, 그냥 Swarm 노드간 가상의 네트워크를 만들어 서로 알아서 연결된다는 소리다. 그리고 이 네트워크에 연결된 노드들에는 신기한 일이 일어나는데, 만약 서비스를 실행하며 80 포트를 열었다면, 모든 노드의 80 포트가 같이 열리는 것이다. 이게 무슨 소리냐면 일단 서비스가 돌아만 가면 core-01로 접속하던 core-02로 접속하던 같은 서비스에 연결된다는 말이다.

    정말 그럴까? 직접 접속해보자. 위에 말했듯 필자의 Flask 데모 애플리케이션은 core-05 (172.17.8.105) 에서 돌아가고 있다. 먼저 core-01 (172.17.8.101) 로 접속을 해 보겠다.


    문제 없이 접속이 된다. 그럼 core-02 (172.17.8.102) 는 어떨까?


    마찬가지로 아무 문제 없이 접속이 되는 것을 확인할 수 있다. 놀랍지 않은가? 이것은 서버 오케스트레이션이 추구하는 일 중 하나이기도 하다. 수백 ~ 수천대의 서버들이 작동하는데 그 중 웹 서버는 대체 어디서 돌아가는지 관리자가 알고 있어야 한다면 상상만 해도 끔찍할 것이다. 오케스트레이션이 잘 진행된 환경이라면 그 모든 과정을 인프라가 스스로 결정하고 사용자에게 매끄럽게 연결해 줄 것이다. 관리자의 흰머리와 피부 상태도 훨씬 좋아지지 않을까.

    부하 분산하기

    그럼 잠깐 다른 상황을 가정해 보겠다. 우리 웹 애플리케이션의 매력을 알아챈 사용자들이 미친듯이 몰리는 바람에, 서버가 골로 가기 직전의 지옥도가 펼쳐지고 있다고 해보자. 이럴 때는 서비스가 돌아가는 컨테이너를 여러개 만들어 부하를 분산시킬 수 있다. Docker Swarm 답게 역시 간단한 명령어 조금으로 구현이 가능하다.

    docker service scale 서비스이름=5
    

    위 명령어로 지정한 서비스의 컨테이너를 5개 더 만들어 부하 분산을 할 수 있다. 서비스이름 scaled to 5 라는 메시지가 출력됬을 것이다. 혹시 내 Swarm 클러스터의 노드가 5개 미만이더라도 한 노드에 컨테이너 2개 이상을 배치해 문제 없이 가동시킬 수 있다. docker service ps 서비스이름 명령어를 입력해서 진행 상태 등을 확인할 수 있다. 아래는 필자의 출력값이다.

    7mgur7xeylq2  flaskontesting.1      p0bailey/docker-flask:latest  core-05  Running        Running 45 seconds ago                                          
    owqgn5g7ognl  flaskontesting.2      p0bailey/docker-flask:latest  core-01  Running        Running 4 minutes ago                                       
    xwwn6blyxs8r  flaskontesting.3      p0bailey/docker-flask:latest  core-02  Running        Running 52 seconds ago                                      
    ypk6ht23mig3  flaskontesting.4      p0bailey/docker-flask:latest  core-03  Running        Running 4 minutes ago                                                                   
    itv3ms2jm3i2  flaskontesting.5      p0bailey/docker-flask:latest  core-04  Running        Running 3 minutes ago                                       
    

    잘 돌아가고 있는 것을 확인할 수 있다. 혹시라도 일부 컨테이너가 시작을 실패한 경우 docker service update 서비스이름 --force 명령어로 강제 재시작 시킬 수 있다. 물론 명령어는 update 이지만 아무 변경점 없이 --force 깃발을 달아 재시작만 할 수 있다. 자세한 내용은 여기 참조.

    DB와 함께 구동되는 웹 서비스 구축

    잠깐 잊고 있었는데, GitHub 페이지 같은 정적 웹 서비스가 아닌 이상 DB 없이 혼자 구동되는 서비스는 거의 없다. DB 컨테이너를 따로 만들어 웹 애플리케이션 자체와 연결되는 구성을 해볼 것인데, 사실 전혀 어려운 건 없다. 그리고 우리는 이미 비슷한 구성을 이전에 해본 적이 있다. DockerFile과 Docker-Compose를 살펴볼 때 Flask와 Redis 컨테이너가 서로 연결되는 웹 애플리케이션을 이미 만들어 보지 않았는가? 이번에도 Flask와 Redis를 가지고 놀아 보겠다. 단지 다른 점은 Swarm 클러스터 위에 올라간다는 것 뿐이다.

    여기서 잠깐 재미있는 구성을 해 보겠다. 조금 전 우리가 올린 Flask 컨테이너는 기본적으로 제공되는 Ingress 네트워크를 통해 외부와 통신했다. 그럼 Redis DB도 Ingress에 배치해 외부에 노출된 상태로 Flask와 통신해야 할까? 아니다. 서버간 통신용 네트워크를 하나 더 만들면 된다. 외부에서 접근하지 못하는 내부 컨테이너간의 네트워크에 DB를 배치해 편리함과 보안을 전부 잡을 수 있다.

    아래의 명령어로 backend 라는 이름의 오버레이 네트워크를 생성할 수 있다.

    docker network create --attachable \
      --driver overlay \
      backend
    

    정상적으로 생성되었다면, 아마 04vxf5jq7v294qha330okd2aw와 같은 네트워크 ID값이 출력될 것이다. docker network ls 명령어로 생성된 네트워크들을 확인할 수 있다.

    NETWORK ID          NAME                DRIVER              SCOPE
    04vxf5jq7v29        backend             overlay             swarm
    d0c72d79896d        bridge              bridge              local
    8817021f578e        docker_gwbridge     bridge              local
    735c71fe7b49        host                host                local
    ul98o5yxor9n        ingress             overlay             swarm
    12767a2f2080        none                null                local
    

    저기 backend가 보인다. 제대로 잘 생성되었다. 덤으로 ingress 네트워크도 잘 지내고 있는 것을 볼 수 있다.

    그럼 바로 Redis 서비스를 생성할 차례다. 아래 명령어로 진행할 수 있다.

    docker service create --name redis \
      --network=backend \
      redis
    

    위에서 진행했던 것처럼, docker service ls 명령어로 생성한 서비스들을 확인할 수 있다.

    ID            NAME            MODE        REPLICAS  IMAGE
    3pyk3b8bo9t0  flaskontesting  replicated  5/5       p0bailey/docker-flask:latest
    5gnyczzqzxq6  redis           replicated  0/1       redis:latest
    

    역시 잘 생성되고 있다.

    그럼 정말 이 Redis를 사용해서 무언가를 해보자. 이전 포스트에서 만들었던 Flask와 Redis가 함께 작동하며 내가 이 사이트에 몇번 방문했는지 알려주는 카운터 애플리케이션을 기억하나? 비슷한 구현을 해 보겠다. 이전 포스트에서는 Docker-Compose를 사용했지만, 이번에는 미리 빌드된 이미지를 사용하겠다. 중요한 것은 이미지가 아니라 DB와의 연동이니까.

    미리 빌드된 이미지는 Subicura 님의 블로그에서 가져와 사용했다. 정말 감사합니다.

    docker service create --name counter \
      --network=backend \
      --replicas 3 \
      -e REDIS_HOST=redis \
      -p 4568:4567 \
      subicura/counter
    

    위 명령어로 3개로 복제된 backend 네트워크에 연결되고 외부로 4568 포트가 열린 counter라는 이름의 애플리케이션을 실행할 수 있다. 중간에 REDIS_HOST를 지정해줬는데, 별도로 IP를 입력하는 것이 아닌 그냥 호스트 이름만 치면 된다. 오버레이 네트워크가 알아서 그 이름을 찾아 연결해준다. 편하다.

    정상적으로 실행이 되었다면, 생성한 컨테이너로 curl이나 웹 브라우저 접근을 해보자. 한 주소로 접속해서 카운터가 1씩, 총 3번 올라가는 것을 볼 수 있다. 정상적으로 컨테이너가 부하분산 되고 있다는 뜻이다.

    마무리

    이 글을 마무리하는데 정말로 오랜 시간이 걸렸다. 17년 3월 말에 쓰기 시작한 글인데, 8월 말에 마무리했다. 여러가지 바쁜 일도 많았고, 정신 상태도 영 좋지 못했다. 거의 잊어버릴 뻔 했지만, 방치하는 것보다는 어떻게는 마무리를 짓는 것이 옳다고 생각해 남은 시간에 꺼내들었다. Docker Swarm은 정말 편리하고 강력한 도구다. 많이 늦었지만, 누군가에게 도움이 되길 바란다.

  • GitHub 페이지에 댓글창 만들기

    포탈사이트 등에서 제공하는 블로그 서비스의 경우 사용자의 자유도가 적은 대신 많은 기능들이 완성된 형태로 한번에 제공된다. 그 중 하나가 댓글 기능이다. 인터넷에서 글쓴이와 독자가 가장 자연스럽게 의견을 주고받을 수 있는 소통 창구가 바로 댓글창이다. 다만 GitHub 페이지의 기반이 되는 Jekyll은 안타깝게도 댓글 기능을 기본적으로 제공하지 않는다. 그렇지만 크게 문제될 것도 없다. 없으면 만들면 될 것 아닌가?

    Disqus 기반 댓글 기능 넣기

    Disqus라는 어느 웹사이트라도 쉽게 댓글 기능을 집어넣을 수 있는 훌륭한 무료 서비스가 있다. 사이트마다 새로 가입할 필요 없이 페이스북같은 SNS 계정과 연동하여 한 계정으로 Disqus를 사용하는 모든 사이트에 댓글을 남길 수도 있고, 사진이나 동영상 같은 콘텐츠도 첨부할 수 있는 등 매력을 한 컨테이너 가지고 있는데 우리가 마다할 이유는 전혀 없다. 당장 설치해 보자.

    위 링크를 클릭해 Disqus에 접속하여 계정을 생성한다. 생성이 끝나면 메인 페이지에 내던져질 것인데, 오른쪽 상단의 톱니바퀴 아이콘을 누르면 ‘Add Disqus To Site’ 라는 메뉴가 있을 것이다.


    클릭하면 바로 사이트 추가 창으로 옮겨지는 것이 아닌 서비스를 소개하는 페이지가 먼저 뜬다. 당황하지 말고 아래로 쭉 내려 ‘Ready to install Disqus?’ 라는 메시지 아래의 파란 버튼을 누르자. 아래 스크린샷의 파란 버튼 맞다.


    다음 창에서 ‘I want to install Disqus on my site’ 를 클릭한다. 자, 이곳에서 내 사이트 이름과 종류(주제) 등을 정의할 것이다. 적당히 입력하고 넘어가면 요금제를 선택하는 창이 나오는데, 당연히 우리는 Free를 선택하면 된다. 이제 Disqus를 연결하고 싶은 사이트를 고르는 단계다. 우리는 GitHub 페이지를 다루고 있으니 Jekyll을 선택하자. 거의 다 왔다. 이제 코드 몇줄만 GitHub 페이지에 삽입만 하면 된다.


    위 스크린샷의 2번 영역에서 ‘Universal Embed Code’ 링크를 누르면 아래같은 코드가 나올 것이다.


    1번 부분의 코드만 전부 복사해서 내 GitHub 페이지의 _layouts 폴더 안 post.html 파일 안에 넣어주면 된다. 아래는 코드를 삽입한 필자의 GitHub 페이지 post.html 이다.


    이걸로 끝이다. GitHub에 푸시한 후 내 사이트로 접속해보면 이제 모든 포스트 아래에 댓글창이 생긴 것을 확인할 수 있다. 수고하셨다. 이제 소통할 독자만 만들면 된다. ㅠㅠ