Quantcast
Channel: 개발 노트
Viewing all 302 articles
Browse latest View live

[리뷰] C#코딩의 기술 기본편 - 길벗

$
0
0

책이 주었던 느낌


책을 처음 받았을 때 생각보다 아담한 사이즈였고 책을 펼쳐보니 대화식의 짤막한 단원들로 구성이 되어 있어서 기본편 답게 가벼운 내용을 다루겠구나라고 생각했었습니다. 하지만 책을 완독하고 난 후에는 기본편이라고만 보기에는 깊은 내용들이 많이 담겨있었고, 실무에서 반드시 필요한 지식들로 가득했습니다. 마치 이펙티브 시리즈를 보는 것 처럼 각 단원마다 버릴 내용이 없었고, 개그 요소를 섞어가며(저자가 일본인이라서 일본식 개그가 많았지만) 딱딱한 주제들을 재미있게 풀어나가는 필력 또한 감탄스러웠습니다.



이 책에는 신입 개발자 느낌의 래머군과 이 래머군이 업무를 진행하면서 생기는 궁금증들에 대해 조언 또는 토론을 진행하는 악마와 천사가 등장합니다. 악마는 악마답게 그럴싸하지만 완벽한 답이 아닌, 또는 잘못된 답을 알려주고 천사가 이를 비판하며 모범답안을 제시합니다. 이러한 진행 과정이 대화체를 통해 이루어지는데 평소에 개발자들과 주고 받았던 대화들과 비슷한 부분들이 많아서 여러모로 공감을 해가며 재미있게 읽을 수 있었습니다.


이렇게 재미 요소를 넣어가며 쉽게 풀어나가다보니 어떤 주제에서는 조금 더 깊게 다뤄주었으면 좋겠는데 언급만 하고 지나가는 경우가 다소 있었습니다. 이런 부분에서는 언급된 내용들을 단초로 검색을 통해 궁금증을 해소할 수 있었습니다. 너무 자세한 내용을 이 책에서 다루게 된다면 흥미가 떨어질 수도 있을 것 같다는 생각에 기본편이라는 타이틀 답게 이 정도 수준이 책에서 다루는 내용으로 적절한 것 같다고 생각을 했습니다.


책의 구성

책의 구성을 살펴보면 먼저 1장에서는 언어 사양 문제를 다루고 있는데, 이는 비단 C#을 위한 내용만은 아니었습니다. 개인적인 생각으로 이 책은 C#이라기 보다는 C 계열의 객체지향 프로그래밍 언어들 중 어떠한 언어를 사용하는 개발자든 읽으면 많은 도움이 될 것이라고 생각을 합니다. 저 또한 최근에는 자바를 더 많이 사용하고 있는데 책을 읽어 나가며 많은 부분에서 도움이 되었습니다.


2장에서는 라이브러리 문제에 대해 다루고 있는데, 가장 C#에 특화된 장이었습니다. 다른 언어들에는 해당되지 않는 내용들이 많았고, 마지막 자바여 편히 잠들라 라는 단원에서는 제목만 보고 C# 추종자 같은 느낌이 들었지만 그런 내용은 아니었고 C#과 자바의 언어적 지향점이 다르다는 것과 언어마다의 특성을 잘 이해해야 한다는 내용이었습니다. 특히 같은 객체지향 언어라고 해서 쉽게 보고 쉽게 구현해낼 수 있다는 생각이 나중에 큰 화를 부를 수 있겠다는 생각을 하였습니다. 사실 얼마전까지만해도 자바스크립트가 자바랑은 다르긴 하지만 금방 배워서 쓸 수 있겠지라는 생각으로 웹개발에 도전했었는데 나름 잘 구현했다고 생각했던 코드에서 의도하지 않았던 동작을 하고 서비스에 악영향을 미치는 것을 보고 언어에 대해서 제대로 알고 사용을 해야겠다는 것을 느꼈었습니다. 대부분의 문제들이 언어에 대해 제대로 이해하지 못하고 사용한 부분에서 발생했었습니다.


3장에서는 개발 환경 문제에 대해 다루고 있는데, GAC이라는 것은 이 책을 통해 처음 알게되었습니다. 글로벌로 참조를 하여 여러 애플리케이션에서 참조할 수 있다니, 좋은 점도 있겠지만 책에서 언급한 것 처럼 많은 주의를 기울여야 할 것 같았습니다. 그리고 버전에 대한 부분에 대해서도 언급을 하는데 실제로 업무를 하면서 자바스크립트의 특정 라이브러리를 사용하다가 최신 버전으로 버전업을 하니 잘 돌아가던 코드에서 오류가 났던 적이 있었습니다. 널리 알려진 단체에서 개발한 라이브러리에서도 버전업을 하면 이전 버전을 사용하던 부분에서 오류가 발생하는 경우가 간혹 있는데, 하물며 인터넷에 떠도는 각종 라이브러리들은 통보도 없이 변경되는 경우가 허다합니다. 그러므로 버전 변경은 꼼꼼한 확인을 통해 이상이 없다는 것을 검증한 후에 사용을 해야합니다.



4장에서는 알고리즘 문제에 대해서 다루고 있는데, 악마가 조언하는 알고리즘들을 보니 자꾸 저를 보는 것 같아 부끄러운 마음이 들기도 하고 웃기기도 했습니다. 읽는 내내 악마를 보면 자기 주관이 없고 이리저리 흔들리는 모습을 보니 자꾸 거울을 보는 듯한 느낌이 들었습니다.



이에 반해 천사의 경우에는 거두절미하고 코드를 보여줘라는 대사와 함께 추측하지 않고 자신이 알고 있는 팩트를 가지고 조리있게 얘기하는 걸 보고 느끼는 부분이 많았습니다.


마지막 5장은 비주얼 스튜디오에 대한 내용이므로 팁이라 생각하고 가볍게 읽어보면 좋을 것 같습니다.


결론

이 책의 장점은 대화체를 사용한다는 점과 이로 인해 처음부터 끝까지 술술 읽힌다는 것입니다. IT 전문서를 읽다보면 처음 의지와는 달리 점점 흥미를 읽고 포기하는 경우가 많은데 이 책은 끝까지 재미있게 읽을 수 있었습니다. 코딩의 기술 시리즈는 C# 실전편이 존재하고, C#외에도 파이썬과 자바편도 있는데 한번씩 읽어보고 싶은 마음이 들었습니다. 현업에 입문한 신입 개발자들이나 개발에 지쳐 잠시 머리를 식히고 싶은 개발자 분들께 이 책을 추천합니다.

저작자 표시비영리변경 금지

[리뷰] 실전 스프링 부트 워크북 - 한빛미디어

$
0
0



책을 펼치며

평소에 스프링에 대한 관심은 가지고 있었지만 사내에서는 서블릿 기반의 웹 서버를 사용하기 때문에 업무에서 사용할 기회가 없어서 깊이 있게 공부하지는 못하고 있었습니다. 또한 스프링을 장애 없이 현업에서 사용하기 위해서는 깊은 이해가 필요한데 팀원 모두가 공부하고 테스트해보고 적용하기까지는 많은 시간을 필요로 했습니다. 이러한 진입장벽 때문에 스프링은 거의 배제한 채로 비교적 Old한 방식의 서블릿 기반 웹서버를 계속해서 사용해오고 있었습니다.


그러던 중 커뮤니티에서 스프링 부트에 대한 세미나를 듣게 되었고, 급 관심이 생기게 되었습니다. 가장 매력적이었던 부분은 스프링에서 복잡했던 xml 파일 작성부분이 스프링 부트에서는 필요가 없다는 것이었습니다. 스프링 부트 웹 페이지에서 원하는 설정들을 체크박스 형태로 선택한 후에 Generate를 수행하면 기본 프로젝트 구성을 알아서 다 해줍니다. 그러므로 설정은 최소화하고 개발자는 개발에만 신경쓸 수 있게끔 해주고 있기 때문에 이 정도면 팀원들을 설득하고 짧은시간 내에 활용할 수 있을 것 같다는 생각이 들었습니다.



이러한 생각을 가지고 설레는 마음으로 실전 스프링 부트 워크북이라는 책을 읽어보게 되었는데, 표지만 봐도 공부를 하고 싶어지는 욕구가 생겼습니다. 그만큼 최근에 나오는 개발 서적들의 표지나 내용물이 점점 더 깔끔하고 눈에 잘 들어오게 변화하고 있는 것 같습니다.



책의 구성

대부분의 기술 서적들과 같이 시작은 스프링 부트가 무엇인지, 그리고 왜 스프링 부트를 사용해야 하는지에 대해 설명을 해주고 있습니다. 스프링과 스프링 부트의 차이가 무엇인지, 그리고 스프링 부트를 사용하면 무엇이 좋은지에 대해 궁금하신 독자들은 이부분에서 궁금증을 해소하실 수 있을 것입니다.



책의 구성은 기본적으로 이론을 설명해주고, 이론을 활용한 코드를 생략 없이 모두 수록하고 있습니다. 그리고 이 코드에 대한 설명을 뒤에 덧붙이면서 독자의 이해를 도와줍니다. 실행에 필요한 전체 코드를 수록하고 있기 때문에 하나씩 따라 쳐 보면서 직접 어플리케이션을 구현해볼 수 있다는 것이 이 책의 장점이라고 생각합니다.


아쉬웠던 점은 책의 대부분이 텍스트로만 이루어져 있었기 때문에 각 애너테이션 간의 관계나 클래스들 간의 관계 등 이론적인 설명들이 머릿속에 잘 그려지지 않았습니다. 그래서 같은 내용을 여러번 반복해서 읽고, 연습장에 클래스 다이어그램이나 그림을 그려가면서 읽어야 했습니다. 또한, 예제에서 사용되는 css와 js 파일이 이 예제의 프로젝트가 아닌 외부의 프로젝트에서 가져온 것이므로 해당 파일들을 직접 다운받아서 프로젝트에 첨부를 시켜주어야 하기 때문에 초반에 정상적으로 서버를 구동하는데 어려움을 겪었었습니다.(스프링 부트를 처음 사용해봐서 어떤 위치에 css와 js파일들을 위치시켜야 하는지 몰라서)


마치며

책에서 스프링 부트에 대한 깊은 내용은 다루고 있지 않지만 예제를 따라해보며 스프링 부트가 이런 것이다라는 것은 분명하게 느낄 수 있게 해준 책이었습니다. 데이터베이스를 사용하는 부분에 있어서도 현재 DBCP를 사용하는 것에 비해 굉장히 편리했고 매력적이었습니다. 데이터베이스나 네트워크, 보안 관련된 모듈들을 각각 신경써야 했던 기존과는 다르게 스프링 부트를 사용하면 일관된 방식으로 사용할 수 있다는 것 또한 큰 장점이라고 생각합니다. 다음 프로젝트에서는 스프링 부트를 사용하여 개발하는 것을 목표로 더 깊이 있게 살펴봐야겠습니다.

저작자 표시비영리변경 금지

ELK에 Search Guard 적용

$
0
0

nginx 인증을 사용하여 사내 직원들에게 kibana에 접속하도록 하고 있던 중 Popit의 Search Guard로 ES, 키바나 인증 구축포스팅을 보고 적용을 하게 되었다. 적용 과정 중 수차례 삽질을 했었기 때문에 조금 더 상세하게 정리를 해보았다.



Elasticsearch에 Search Guard 설치

  1. install 명령

    $ bin/elasticsearch-plugin install -b com.floragunn:search-guard-5:5.5.0-14
    • 버전은 아래 버전표 참고
  2. tools 디렉토리로 이동

    $ cd<Elasticsearch directory>/plugins/search-guard-<version>/tools
  3. install_demo_configuration.sh 실행

    $ ./install_demo_configuration.sh
    • 실행권한이 없는 경우 chmod +x install_demo_configuration.sh
    • 실행 후 truststore, keystore, kirk 인증서 파일이 생성됨
      • <Elasticsearch directory>/config 디렉토리에 생성됨
      • truststore.jks : root CA와 intermediate/signing CA
      • keystore.jks : 노드 인증서(node certificate)
      • install_demo_configuration.sh를 통해 생성된 인증서 파일들은 미리 생성해놓은 키값을 사용하기 때문에 보안에 취약하므로 production 서비스에서 사용할 경우에는 keystore와 truststore를 생성하여 사용할 것을 권장.
  4. elasticsearch 실행

    $ <Elasticsearch directory>/bin/elasticsearch
    • elasticsearch가 실행 된 후 아래 sgadmin 스크립트를 실행 시켜주어야 Search Guard를 사용하기 위해 필요한 데이터들이 elasticsearch에 생성된다.
  5. sgadmin_demo.sh 실행

    $ cd<Elasticsearch directory>/plugins/search-guard-<version>/tools
    $ ./sgadmin_demo.sh
    • 권한 설정이나 SearchGuard에 대한 설정 파일들은 plugins/search-guard-<version>/sgconfig 디렉토리에 생성됨

    • elasticsearch의 설정에 따라 ip와 port가 localhost의 9300이 아닌 경우에는 sgadmin_demo.sh 파일을 수정하여 호스트와 포트를 지정한다.'

      $ <Elasticsearch directory>/plugins/search-guard-5/tools/sgadmin.sh -cn searchguard_demo -h localhost -p 9300 -cd <Elasticsearch directory>/plugins/search-guard-5/sgconfig -ks <Elasticsearch directory>/config/kirk.jks -ts <Elasticsearch directory>/config/truststore.jks -nhnv
  6. https://localhost:9200 으로 접속 확인

    • 인증 요청 팝업이 출력됨. (이 계정 정보는 sgconfig/sg_internal_user.xml에 정의)


    • 인증에 성공하면 아래와 같은 정보가 출력됨

      {
        "name" : "9t6GokQ",
        "cluster_name" : "searchguard_demo",
        "cluster_uuid" : "itfKNEpHTZGSnbMuhj8ZrA",
        "version" : {
          "number" : "5.5.0",
          "build_hash" : "260387d",
          "build_date" : "2017-06-30T23:16:05.735Z",
          "build_snapshot" : false,
          "lucene_version" : "6.6.0"
        },
        "tagline" : "You Know, for Search"
      }

Kibana에 Search Guard 설치

  1. 플러그인 다운로드

    $ wget https://github.com/floragunncom/search-guard-kibana-plugin/releases/download/v5.4.2-3/searchguard-kibana-5.4.2-3.zip
  2. 플러그인 설치

    $ bin/kibana-plugin install file:///usr/share/kibana/temp/searchguard-kibana-5.4.2-3.zip
  3. /etc/kibana/kibana.yml 설정

    elasticsearch.url: "https://localhost:9200"
    
    ... 생략 ...elasticsearch.username: "kibanaserver"elasticsearch.password: "kibanaserver"
    
    ... 생략 ...elasticsearch.ssl.verificationMode: none
    
    ... 생략 ...
    • elasticsearch URL은 이제 https를 사용
    • username과 password는 elasticsearch 쪽에 sgconfig/sg_internal_user.xml 파일에 지정된 계정을 사용
    • 사설 인증서를 사용하지 않으므로 verificationMode는 none으로 설정
  4. http://localhost:5601 (키바나)로 접속


  5. 브랜드 이미지를 변경하고 싶은 경우에는 config/kibana.yml에서 아래 설정 추가

    searchguard.basicauth.login.showbrandimage: true
    searchguard.basicauth.login.brandimage: "이미지 경로"
    searchguard.basicauth.login.title: "로그인을 해주세요."
    searchguard.basicauth.login.subtitle: "서브 타이틀입니다."
  6. 키바나 재시작 후 접속


logstash 설정

  1. logstash.conf 파일 작성

    input {
      stdin {}
    }
    output {
      elasticsearch {
        hosts => "localhost:9200"
        user => logstash
        password => logstash
        ssl => true
        ssl_certificate_verification => false
        truststore => "<logstash path>/config/truststore.jks"
        truststore_password => changeit
        index => "test"
        document_type => "test_doc"
      }
      stdout{
        codec => rubydebug
      }
    }
  • user와 password는 elasticsearch의 Search Guard 플러그인에 등록된 유저 정보
    • 기본적으로 logstash 용으로 계정이 정의되어 있음.
  • ssl 설정을 true로 한 경우 ssl을 사용한다.
  • 인증서 파일을 사용하여 인증 절차를 수행하는 경우 ssl_certificate_verification을 true로 설정한다.
    • 여기서는 인증 절차를 수행하지 않기 때문에 false로 설정
    • true인 경우 truststore에 대한 설정을 해주어야 한다.

보충 설명

사용자 관리

아래에서 사용되는 설정 파일들은 <elasticsearch path>/plugins/search-guard-5/ 하위에 위치함.


사용자 추가

  1. sgconfig/sg_internal_users.yml 파일에 유저 추가

    guest:
      hash: 
      #password is: guest
  2. tools/hash.sh를 사용하여 패스워드 생성

    $ sh hash.sh
    [Password:]
    $2a$12$izzerIN4R.m6nCDNuCPtWOR/6n/LBudgjPLBS1naNptyF2VuUPwfe
  3. 생성된 해쉬코드를 복사하여 sgconfig/sg_internal_users.yml 파일에 추가

    guest:
      hash: $2a$12$izzerIN4R.m6nCDNuCPtWOR/6n/LBudgjPLBS1naNptyF2VuUPwfe#password is: guest
  4. tools/sgadmin_demo.sh 파일을 실행하여 변경된 사항 적용

    $ ./sgadmin_demo.sh


권한 설정

  1. 사용자에 대한 권한 role 이름을 sgconfig/sg_roles_mapping.xml 파일에 설정 하고, role 이름을 기반으로 사용자들을 해당 role에 추가시켜서 다수의 사용자들에게 동일한 role을 지정할 수 있다.

    • 기본적으로 prefix로 sg_가 붙음

    • 위에서 추가한 guest의 경우 sg_guest로 지정

      sg_guest:
        uesrs:
          - guest
  2. sgconfig/sg_roles.xml 파일 수정

    • 위에서 설정한 role 이름에 대한 권한을 지정한다.

    • 여기서는 guest로 들어온 경우 read only 권한을 부여

      sg_guest:
        cluster:
          - UNLIMITEDindices:
          '*':
            '*':
              - READ
    • 대문자로 표시되어 있는 값들은 sgconfig/sg_action_groups.yml 파일에 정의되어 있다.

      • 위에 설정한 READ의 경우 아래와 같이 설정됨

        READ:
          - "indices:data/read*"
          - "indices:admin/mappings/fields/get*"
  3. 변경된 사항을 적용하기 위해 tools/sgadmin_demo.sh 실행

    $ ./sgadmin_demo.sh

elasticsearch.yml 설정

http.host: 0.0.0.0logger._root: DEBUG######## Start Search Guard Demo Configuration ########searchguard.ssl.transport.keystore_filepath: keystore.jkssearchguard.ssl.transport.truststore_filepath: truststore.jkssearchguard.ssl.transport.enforce_hostname_verification: falsesearchguard.ssl.http.enabled: truesearchguard.ssl.http.keystore_filepath: keystore.jkssearchguard.ssl.http.truststore_filepath: truststore.jkssearchguard.authcz.admin_dn:
  - CN=kirk,OU=client,O=client,L=test, C=decluster.name: searchguard_demonetwork.host: 0.0.0.0######## End Search Guard Demo Configuration ########
  • keystore/truststore 를 직접 생성하지 않고 이미 생성되어 있는 것을 사용하는 경우 아래 명령으로 인증 정보 확인

    $ keytool -list -v -keystore kirk.jks
    • install_demo_configuration.sh를 통해 생성된 kirk.jks 파일의 패스워드는 changeit
  • 이 설정 값은 install_demo_configuration.sh 쉘스크립트를 실행하면 자동으로 추가된다.


keystore/truststore 생성

자바에 포함된 보안관련 어플리케이션인 keytool을 사용

  1. keystore 생성 (인증서)

    $ keytool -genkey -alias hive-key -keyalg RSA -keypass changeit -storepass changeit -keystore keystore.jks
  2. 위에서 생성한 keystore.jks 인증서를 server.cer 파일로 내보냄

    $ keytool -export -alias hive-key -storepass changeit -file server.cer -keystore keystore.jks
  3. truststore 파일을 만들고 인증서를 truststore에 추가

    $ keytool -import -v -trustcacerts -file server.cer -keystore truststore.jks -keypass changeit
  4. keystore.jks와 trusstore.jks 생성 완료

    Owner: CN=yongho, OU=vinus, O=server, L=Seoul, ST=Samsung, C=16201
    Issuer: CN=yongho, OU=vinus, O=server, L=Seoul, ST=Samsung, C=16201
    Serial number: 3ee66345
    Valid from: Thu Jul 13 05:27:44 UTC 2017 until: Wed Oct 11 05:27:44 UTC 2017
    Certificate fingerprints:
             MD5:  58:DD:2D:D2:11:93:8C:E4:EF:96:4C:0F:8D:04:52:96
             SHA1: 93:5F:BD:68:04:6C:E6:CC:7A:DC:08:79:0D:EB:B4:C3:69:38:EF:A1
             SHA256: 57:FB:66:40:47:A0:6B:1A:96:4B:91:31:60:6C:51:F7:7E:2B:04:29:9A:EE:EE:8E:AB:5A:23:43:F3:4B:E4:83
             Signature algorithm name: SHA1withDSA
             Version: 3
    
    Extensions:
    
    #1: ObjectId: 2.5.29.14 Criticality=false
    SubjectKeyIdentifier [
    KeyIdentifier [
    0000: 33 4D 88 F3 C9 AC 12 DF   3F 92 1D 96 50 9C 36 2E  3M......?...P.6.
    0010: E4 11 2E 51                                        ...Q
    ]
    ]
    

트러블슈팅

zen_unicast 관련 에러

[2017-07-13T06:04:03,175][ERROR][c.f.s.t.SearchGuardRequestHandler] Error validating headers
[2017-07-13T06:04:03,191][WARN ][o.e.d.z.UnicastZenPing   ] [vOvmwD5] [1] failed send ping to {#zen_unicast_127.0.0.1:9300_0#}{UV7v4BgFTaSO3E3F6Ng2DQ}{127.0.0.1}{127.0.0.1:9300}
java.lang.IllegalStateException: handshake failed with {#zen_unicast_127.0.0.1:9300_0#}{UV7v4BgFTaSO3E3F6Ng2DQ}{127.0.0.1}{127.0.0.1:9300}
        at org.elasticsearch.transport.TransportService.handshake(TransportService.java:386) ~[elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.transport.TransportService.handshake(TransportService.java:353) ~[elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.discovery.zen.UnicastZenPing$PingingRound.getOrConnect(UnicastZenPing.java:401) ~[elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.discovery.zen.UnicastZenPing$3.doRun(UnicastZenPing.java:508) [elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:638) [elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37) [elasticsearch-5.4.3.jar:5.4.3]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_131]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_131]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]

  • conf/elasticsearch.yml 설정에서 network.publish_host와 network.bind_host가 모두 설정되어 있는 경우 network.publish_host 설정을 제거하면 해결됨

    cluster.name: myclusternode.master: truenode.data: truediscovery.zen.ping.multicast.enabled: falsenumber_of_nodes : 1minimum_master_nodes: 1path.logs: .node.name: ElasticStack.0.0.0.0# network.publish_host: 0.0.0.0network.bind_host: "0.0.0.0"
    ... 생략 ...
  • 참고


Someone (/172.19.0.8:38490) speaks http plaintext instead of ssl, will close the channel

  • Search Guard 사용 시 http 통신 또한 ssl로 사용하도록 설정해둔 경우 기존에 http를 사용하여 logstash나 kibana를 사용하고 있었기 때문에 이 통신이 https가 아니라는 오류가 출력된다.

  • logstash나 kibana에 https로 통신을 하도록 설정하던가 https 통신을 사용하지 않도록 설정하도록 함.

  • 여기서는 https 통신을 사용하지 않는 것으로 설정

  • conf/elasticsearch.yml 파일 수정

    ... 생략 ...searchguard.ssl.http.enabled: falsesearchguard.ssl.http.keystore_filepath: /usr/share/elasticsearch/config/keystore.jkssearchguard.ssl.http.keystore_password: changeitsearchguard.ssl.http.truststore_filepath: /usr/share/elasticsearch/config/truststore.jkssearchguard.ssl.http.truststore_password: changeit
    ... 생략 ...
    • searchguard.ssl.http.enabled을 false로 설정

Not yet initialized 에러

[2017-07-14T10:23:06,639][INFO ][c.f.s.c.IndexBaseConfigurationRepository] searchguard index does not exist yet, so no need to load config on node startup. Use sgadmin to initialize cluster
[2017-07-14T10:23:06,639][INFO ][o.e.g.GatewayService     ] [9t6GokQ] recovered [0] indices into cluster_state
[2017-07-14T10:23:08,171][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
[2017-07-14T10:23:08,200][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
[2017-07-14T10:23:10,708][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
[2017-07-14T10:23:13,212][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
[2017-07-14T10:23:15,714][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
  • 키바나에서 연결 요청을 하는 경우 위와 같은 에러 발생

  • Search Guard 플러그인에 대한 초기 설정이 제대로 이루어지지 않아서 발생하는 에러이다.

  • 이는 sgadmin_demo.sh 실행이 실패했다는 것을 의미한다.

  • 실패한 경우를 보면 아래와 같다.

    $ ./sgadmin_demo.sh
    Search Guard Admin v5
    Will connect to localhost:9300
    ERR: Seems there is no elasticsearch running on localhost:9300 - Will exit
    • 여기서는 elasticsearch에 접속하지 못해서 발생하는 에러였는데 실제로 elasticsearch가 구동 중이지 않거나 host 또는 port가 맞지 않았기 때문에 발생하였다.
    • host와 port가 맞지 않은 경우 sgadmin_demo.sh 파일을 수정하여 호스트와 포트를 지정
  • 정상적인 경우에는 아래와 같은 메시지가 출력된다.

    Search Guard Admin v5
    Will connect to 192.168.10.211:9300 ... done### LICENSE NOTICE Search Guard ###
    
    If you use one or more of the following features in production
    make sure you have a valid Search Guard license
    (See https://floragunn.com/searchguard-validate-license)
    
    * Kibana Multitenancy
    * LDAP authentication/authorization
    * Active Directory authentication/authorization
    * REST Management API
    * JSON Web Token (JWT) authentication/authorization
    * Kerberos authentication/authorization
    * Document- and Fieldlevel Security (DLS/FLS)
    * Auditlogging
    
    In case of any doubt mail to <sales@floragunn.com>###################################
    Contacting elasticsearch cluster 'searchguard_demo' and waitfor YELLOW clusterstate ...
    Clustername: searchguard_demo
    Clusterstate: GREEN
    Number of nodes: 1
    Number of data nodes: 1
    searchguard index does not exists, attempt to create it ... done (auto expand replicas is on)
    Populate config from /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/
    Will update 'config' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_config.yml
       SUCC: Configuration for'config' created or updated
    Will update 'roles' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_roles.yml
       SUCC: Configuration for'roles' created or updated
    Will update 'rolesmapping' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_roles_mapping.yml
       SUCC: Configuration for'rolesmapping' created or updated
    Will update 'internalusers' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_internal_users.yml
       SUCC: Configuration for'internalusers' created or updated
    Will update 'actiongroups' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_action_groups.yml
       SUCC: Configuration for'actiongroups' created or updated
    Done with success 

참고


저작자 표시비영리변경 금지

[리뷰] 알고리즘 트레이닝 - 인사이트

$
0
0

책을 펼치며

개발자로 일을 해오면서 회사에 취업을 하거나 이직을 하려 할 때 가장 걱정이 많이 되었던 부분이 알고리즘이었습니다. 큰 회사일 수록 알고리즘 풀이에 대한 난이도가 올라가고, 풀어야 할 문제들의 숫자도 점점 늘어났습니다. 알고리즘 문제를 과제로 해결해서 제출해야 될 때도 있고, 면접 보기 전에 실기 시험으로 풀이를 하기도 하고, 면접 중에 화이트보드에 그려가며 알고리즘을 풀어내야 할 때도 있었습니다. 개발자에게 필요한 기본 지식 같은 경우에는 책을 보고 공부를 하거나 겪었던 경험에 의해서 대답하기가 수월했던 반면 알고리즘은 항상 커다란 벽처럼 느껴졌었습니다. 마치 어렸을 때부터 영어공부를 해왔지만 아직도 영어 울렁증에서 벗어나지 못하는 것처럼 알고리즘 또한 내가 과연 극복해낼 수 있을까 싶은 부분이라고 생각해왔고 지금도 마찬가지 입니다.


알고리즘 문제 풀이 능력을 향상 시키기 위해 스터디 그룹을 결성해서 같이 공부도 해보고, 개인적으로 책을 사서 공부를 해보기도 했지만 성과가 나타나기까지 너무 오랜 시간이 걸렸고 문제 하나를 풀어내도 다음 문제에서 막히다 보니 오래 지속하기가 힘들었었습니다. 그러다보니 결과적으로 알고리즘 공부는 항상 끝이 흐지부지되고 소홀해지는 것 같습니다.



이 책을 처음 받자마자 두께와 수록된 문제들에 살짝 압도당했었습니다. 이걸 과연 다 보고 문제들을 풀어낼 수 있을까? 내용 역시 만만치 않게 어려웠습니다. 솔직한 평가로 아직 제가 볼 레벨은 아니라는 생각이 들었습니다. 애초에 대상이 경시대회를 준비하는 사람들에게 맞춰져있었고, 책을 보기 위한 사전 지식 또한 필요합니다. 예를 들어, 책에서는 각 알고리즘에 대해 빅오표기법으로 비교를 하고 있는데, 빅오표기법을 모르는 상태에서 보면 해당 내용들을 온전하게 이해할 수가 없습니다. 그리고 자료구조에 대해서도 어느정도 기반 지식이 있어야 이해할 수 있는 부분들이 있습니다.


책의 구성


먼저 첫 장을 살펴보면, 경시 대회에서 유용할만한 팁들을 알려주고 있습니다. 저의 경우에는 경시대회에 나갈 생각은 없지만 이 내용들이 면접을 볼 때 아주 유용할만한 팁들이라고 생각합니다. 어떠한 마음가짐으로 문제를 풀어나가야하는지, 그리고 어떠한 방식으로 접근을 해야하는지 등등 도움이 될만한 내용들을 담고 있었습니다.



그 다음 장부터는 본격적으로 알고리즘에 대해 소개를 하고 있는데, 먼저 이론 설명부터 시작해서 이해하기 어려운 부분에 대해서는 그림으로 설명하기도 하고, 코드를 직접 첨부하여 설명을 해주기도 합니다. 거의 공백이 없이 빽빽하게 설명이 되어 있기 때문에 진도가 술술 나가지는 않았습니다. 문제들도 대부분 저에게는 어려운 수준이어서 저의 독서 성향 상 진도가 빠르게 나가지 않으면 도중에 다른 책으로 갈아타는 경우가 많아서 이론 위주로 책을 빠르게 한번 보고 문제 풀이는 나중에 하자는 전략으로 읽기 시작했습니다.


마치며


사전 지식도 필요하고 결코 쉽지 않은 책임에도 불구하고 이 책이 매력적이었던 부분은 1600개 이상의 문제를 수록하고 있다는 것이었습니다. 너무 많은 문제들을 풀어야해서 시작하기도 전에 좌절해버릴 수도 있겠지만 이를 극복해낸다면 더 이상 알고리즘에 대한 걱정은 하지 않아도 될 것 같다는 생각이 들었습니다. 아직 이 책의 반에 반도 흡수하지 못했다고 생각하지만 그 동안의 알고리즘 공부 경험 상 시작 당시의 의욕만큼 포기하는 속도가 빨랐던 것 같았기에 이번에는 급하게 생각하지 않고 조금씩 흡수해 볼 생각입니다.

저작자 표시비영리변경 금지

[리뷰] Node.js 6.x 블루프린트

$
0
0



책을 선택한 이유

최근 진행 중인 프로젝트에서 오픈소스를 활용하고 있는데 오픈 소스의 기능에 더해서 추가적으로 제공을 해야하는 기능이나 권한과 같은 문제에 의해 제한을 해야 하는 부분들이 생겨서 오픈 소스를 조금 고쳐서 사용해야하는 이슈가 발생했었습니다. 웹 개발에 대한 짧은 경험이 있었기 때문에 살짝 수정하는 것은 문제가 없을 것이라 판단하고 소스를 열어봤더니 전혀 이해할 수 없는 문법들이었습니다. 바로 node.js로 되어 있었는데, npm 사용법 조차 제대로 몰랐었기 때문에 시작부터 포기하고 싶은 마음이 들었습니다.


Node.js로 되어 있는 코드를 제대로 이해하고 싶기도 했고, 실제로 Node.js를 사용하면 어떠한 것들을 할 수 있는지 궁금했기 때문에 이 책을 선택하고 살펴보기 시작했습니다. 책을 받고 보니 깔끔한 표지에 그렇게 두껍지 않았기 때문에 가볍게 읽어볼 수 있겠다는 생각이 들었고, 다 읽고 나면 왠만큼은 오픈 소스 코드를 이해할 수 있겠구나 라는 기대감을 가지게 되었습니다.


책의 구성

책이 두껍지 않은 만큼 이론적인 설명은 최소화 되어 있다는 느낌이 들었습니다. 그리고 이 책의 대상은 자바스크립트, CSS에 대한 초중급의 지식이 필요하고, 웹 개발에 필요한 일부 지식을 가지고 있는 독자들을 대상으로 하기 때문에 이론적인 부분에 대해서는 친절하게 설명해주지는 않습니다. 대신에 여러 유형의 프로젝트들을 하나씩 따라해보면서 저자의 노하우를 흡수할 수 있게끔 구성이 되어 있었습니다.



개인적으로 책에 수록된 예제는 정말 마음에 들었습니다. Node.js 뿐만 아닌 여러 지식들이 담겨져 있었고, 무엇보다 따라하며 만들어볼 수 있는 페이지가 깔끔하게 잘 만들어져 있었기 때문에 잘 배워서 이 템플릿 위에 웹 페이지를 하나 만들어봐도 좋겠다는 생각이 들었습니다.


주의해야할 점

처음에 언급했듯이 완전 초급자가 대상이 아니기 때문에 첫 예제부터 많은 내용을 담고 있습니다. 각종 미들웨어들을 짧은 소개와 함께 한꺼번에 설치해서 사용하기도 하고, 부트스트랩은 당연히 알고 있지? 하는 것과 같이 별다른 언급 없이 부트스트랩을 사용하고 있습니다. 또한 몽고 DB 미들웨어를 설치해서 사용을 하기도 하고, 암호화와 인증 처리까지 다룹니다.


저의 경우에는 기존에 부트스트랩으로 프로젝트를 했었던 경험이 있었고, 데이터베이스나 인증 관련 부분에도 경험이 있기 때문에 읽어나가는데 문제가 없었지만 이에 대한 경험이 없으신 분들께는 멘붕이 오지 않았을까하는 생각이 들었습니다.

하지만 가장 간단한 웹 페이지부터 시작해서 미들웨어를 하나씩 차근히 붙여 나가는 식으로 소개를 해주는 책들도 좋지만 이렇게 실용적인 예제들로 구성된 책도 괜찮구나라는 생각이 들었습니다.



아쉬운 점

하지만 설명보다는 코드양이 많아서 기계적으로 따라친다라는 느낌이 많이 들었습니다. 이걸 하나씩 전부 다 따라치는 것은 지루한 과정이고 그다지 도움이 되지 않는다고 생각합니다. 그래서 라우팅을 처리하는 부분이나 프로퍼티를 설정하고 가져다 쓰는 등의 코드는 직접 따라 쳐보시되 그 외 HTML이나 CSS 코드 부분은 github repository를 clone 하셔서 복사&붙여넣기 하며 진행하셔도 나쁘지 않을 것이라 생각합니다.

저 또한 몰랐던 부분들은 직접 따라쳐보며 진행했고, 단순 타이핑을 요구하는 부분은 복사, 붙여넣기 해가며 진행하였습니다.


마치며

책의 마지막에 지속적인 통합에 대한 부분도 다루고 있는데, 책의 주제에는 벗어난 감은 있지만 저 또한 이부분이 굉장히 중요하다고 생각하기 때문에 주의 깊게 읽어보았습니다. 저자 또한 책의 주제와는 다르다고 생각해서인지 간단하지 않은 내용들을 짧게 설명한 부분은 조금 아쉬웠습니다. 하지만 이런식으로도 구성이 가능하다는 것을 알게된 것만으로도 저에게는 큰 도움이 되었습니다.

끝으로 이 책을 읽고 난 뒤에 저자의 노하우들을 조금이나마 경험 해볼 수 있어서 좋았고, 책에 담긴 내용들을 보고 있자니 제가 업무에서 얻은 것들을 정리해나가는 방식과 굉장히 비슷해서 뭔가 익숙한 느낌이 들었습니다. 책 전반적으로 설명보다는 개발 노트 같은 느낌이어서 호불호가 있을 것 같긴 하지만 저는 나름 괜찮았다고 생각합니다. 이론에 대한 설명이 담긴 Node.js 프로그래밍 과 같은 책 옆에 두고 함께 보면 좋을 것 같습니다.

저작자 표시비영리변경 금지

[리뷰] 인프라 엔지니어링 첫걸음

$
0
0

책을 펼치며


현재 개발 중인 프로젝트를 진행하면서 다양한 것들을 경험해보게 되었는데, 그 중 하나가 클라우드였습니다. 개인적으로 연습삼아 조금 사용해본 것에 더해서 실제 프로덕트를 서비스 하기 위해서 더 깊이 있게 공부하고 테스트해보게 되었습니다. 클라우드를 제공하는 업체별로 다양한 서비스들을 제공하고 있었는데, Google Cloud Platform의 앱엔진이라던가 AWS의 Elastic Beanstalk와 같은 PaaS 서비스를 이용하면 서버 관리에 대해 크게 신경쓰지 않아도 서비스를 하는데 무리가 없겠다는 생각이 들었었습니다. 그래서 이러한 클라우드에 대한 지식을 가진 클라이언트 프로그래머만 있으면 프로젝트를 진행하는데 별 문제가 없겠다는 생각과 함께 현재 저의 직업인 서버 개발자의 미래가 불투명해지는거 아닌가 하는 걱정이 들기 시작했었습니다.


이번에 경험을 더 해보고 나니 클라우드의 서비스를 단순히 이용만 하는 것을 그렇게 어렵지 않았지만, 수많은 서비스들 중 어떠한 서비스가 우리 프로젝트에 잘 맞는지, 그리고 어떠한 정책에 의해서 서버를 스케일 인/아웃 하고, 아키텍처를 설계할 것인지에 대해 해결책을 제시하는 것은 그리 쉽지 않은 일이었습니다. 아무리 서버 관리를 클라우드 업체에서 해준다고 하더라도, 장애나 보안, 트래픽에 대한 대응을 위해서는 서버 관리나 인프라 관리에 대한 깊은 지식이 필요하다는 것을 깨달았습니다.


인프라 엔지니어링 첫걸음이라는 책은 인프라에 대한 기반 지식을 쌓기에 좋은 책이라고 생각합니다. 인프라에 대해 잘 모르는 사람에게 기초 지식을 알려주고, 클라우드에 대한 경험이 적은 사람에게 조심해야 될 사항들과 서비스를 이용하기에 앞서서 생각해봐야 할 것들에 대해 경험에서 우러나오는 조언들이 많이 담겨져 있습니다.


책의 구성


이 책은 처음부터 순서대로 봐야 더 효과가 좋은 책이라고 생각합니다. 먼저 인프라에 대해 이해할 수 있도록 기반 지식을 습득할 수 있는 1장은 네트워크에 대한 기초라고 생각하시면 될 것 같습니다. 많이 들어보았던 OSI 7계층에 대한 내용이 담겨져 있으므로 뒤에 이어질 내용들을 확실하게 이해하기 위해서는 꼭 선행되어야 한다고 생각합니다.



2장에서는 클라우드에 대한 기초 지식을 담고 있는데 첫 부분에 수록된 인프라를 제공하는 기존의 서비스에서 현재에 이르기까지의 변천과정에 대해서는 몰라도 되는 내용이라고 생각은 하지만 알아두면 현재의 시스템이 왜 이렇게 되었는가를 이해하는데 도움이 될 것이라고 생각합니다. 특히 IaaS, PaaS, SaaS는 클라우드를 다루는 내용에서 자주 등장하는 개념이므로 꼭 이해를 하고 가는 것이 좋습니다. 그 외에도 클라우드에 대한 기초 지식들이 많이 담겨져 있으므로 정독하고 나면 도움이 많이 될 것이라 생각합니다.



3장은 본격적으로 클라우드를 활용하기 위해 도움이 될만한 내용들을 담고 있는데 개인적으로 가장 도움이 많이 되었었습니다. 앞서 언급했던 것과 같이 현재 진행 중인 서비스의 런칭을 앞두고 고민 중이었던 부분들에 대해 경험에서 우러나는 조언들이 많이 담겨져 있었기 때문입니다. 이 장을 읽고나니 너무 안일하게 서비스를 준비하고 있었다는 생각이 들었고, 이 책에서 알려주는 꿀팁들을 잘 활용해서 재정비를 할 수 있었습니다.



4장에서는 장애 대응에 대한 내용이 담겨져있는데, 개발 측면에서의 장애대응 뿐만 아니라 사람과 사람간의 관계에 대해서도 조언을 해주고 있었습니다. 이 책을 읽다보면 기술적인 책에 더해서 마치 경험 많은 회사 선배가 조언을 해주고 있다는 느낌이 들었습니다. 아직은 런칭까지의 시간이 있다보니 장애 대응에 대해서는 크게 신경쓰고 있지 않았는데 이 책에 나와있는 고려사항들을 잘 기록해두고 하나씩 체크를 해보면 큰 도움이 될 것 같습니다.


5장은 보안에 관련된 내용이었는데, 깊이 있는 내용은 아니지만 클라우드 서비스를 이용하는 독자들에게는 충분한 보안 지식이라고 생각을 합니다. 그래서 여기에 언급되는 내용들을 잘 숙지해두었다가 필요한 부분에 있어서는 다른 책이나 검색을 통해서 깊이 있는 지식을 습득한다면 클라우드에 있어서의 보안은 왠만큼은 다 해결될 것 같다는 생각이 들었습니다.



뒤에 이어지는 내용들은 데브옵스에 대한 것과 인프라 엔지니어들이 앞으로 나아가야할 방향에 대해 조언을 해주고 있으므로, 실무적인 내용은 1~5장까지라 생각합니다. 이 내용들만 잘 습득해도 클라우드 환경에서 개발을 하는데 충분히 도움이 되겠지만, 더 나은 엔지니어가 되기 위해서 6~7장의 내용도 찬찬히 읽어보시면 좋을 것 같습니다.


아쉬운 점

이 책에 대해 아쉬웠던 점은 크게 없었습니다. 첫걸음이라는 타이틀과 같이 그리 두껍지 않은 것도 좋았고, 내용 또한 쉽게 술술 읽히는 책이었습니다. 다만 2장의 내용이 같은 내용을 반복한다는 느낌이 들었지만 크게 거부감이 들지는 않았습니다. 만약 사내에 신입 개발자가 들어온다면 필독하라고 권해줄만한 책이라고 생각합니다.


마치며


이 책은 여러명의 저자가 작성한 책이었는데, 첫 부분에 각 저자들의 캐릭터가 소개되어서 각 장을 작성한 저자의 이미지가 떠올라서 더 집중이 잘 되었던 것 같습니다. 별 것 아닌것 같은 컨셉인데 다른 책들과 차별되어서 신선하게 다가왔습니다. 그래서 책을 읽는 내내 선배한테 조언 듣는 기분으로 읽어나갈 수 있었습니다.


그리고 나름 클라우드 서비스 아키텍쳐를 설계 해보면서 고민을 많이 했다고 생각했었는데, 책을 읽다보니 간과한 부분들이 많이 있었습니다. 사내에 조언을 해줄 선배가 없는 현재로써 큰 도움이 되었던 책이었습니다. 현 프로젝트 뿐만 아니라 앞으로의 프로젝트에서도 항상 더 나은 서비스를 위해 더 많이 고민을 해봐야겠습니다.

저작자 표시비영리변경 금지

[AWS] EC2 종료 시 filebeat 정상 종료 확인 및 대기

$
0
0

오토스케일링 설정이 되어 있는 경우 EC2 종료 시 약 1시간까지 종료 대기가 가능하다. 이 때 서비스를 활용하면 인스턴스 종료 시에 서비스를 종료하는 과정에서 원하는 프로세스를 체크하여 정상 종료를 확인 한 후에 종료시킬 수가 있게 된다.  Elastic Beanstalk의 AMI인 Amazon Linux 환경에서는 chkconfig를 사용하여 서비스를 등록할 수 있다.



systemd unit files

  • /etc/systemd/system 디렉토리 하위에 unit file들 정의

  • unit_name.type_extension 형식으로 파일명을 지정

  • Unit 섹션에서 사용할 수 있는 옵션

    옵션내용
    DescriptionUnit에 대한 설명. 이는 systemctl status 명령으로 출력됨
    DocumentationUnit에 대한 문서를 참조하는 URI 목록 제공
    AfterUnit이 시작되는 순서를 정의. 지정된 Unit After가 활성화 된 후에만 시작됨
    Requires다른 Unit에 대한 종속성을 구성. 필요한 Unit이 하나라도 활성화 되지 못하면 해당 Unit은 수행되지 않음
    WantsRequires보다는 약한 의존성을 구성. 나열된 Unit들 중 하나라도 성공적으로 시작되면 수행됨.
    Conflicts네거티브 의존성을 구성. Requires와 반대. 나열된 Unit 중 하나라도 활성화가 되면 수행되지 않음.
  • Service 섹션에서 사용할 수 있는 옵션

    옵션내용
    TypeExecStart 및 관련 옵션에 영향을 주는 Unit 프로세스 시작 유형을 구성.
    ExecStartunit이 시작 될 때 실행될 명령 또는 스크립트를 지정
    ExecStopunit이 종료 될 때 실행될 명령 또는 스크립트를 지정
    Restartsystemctl 명령에 의한 완전 중지를 제외하고 프로세스가 종료 된 후 서비스가 다시 시작됨
    RemainAfterExitTrue로 설정하면 모든 프로세스가 종료 되더라도 서비스가 활성으로 간주됨.
    • Type의 설정 값
      • simple : 기본값. 시작된 ExecStart 프로세스는 서비스의 주요 프로세스
      • forking : 시작된 ExecStart 프로세스는 서비스의 주요 프로세스가 되는 하위 프로세스를 생성. 시작이 완료되면 상위 프로세스는 종료됨
      • oneshot : simple과 유사하지만 결과 unit을 시작하기 전에 프로세스가 종료됨
      • dbus : simple과 유사하지만 주 프로세스가 D-Bus 이름을 얻은 후에만 후속 unit이 시작됨
      • notify : simple과 유사하지만 결과 unit은 sd_notify() 함수를 통해 통지 메시지가 전송 된 후에만 시작됨
      • idle : simpe과 유사하지만 서비스 바이너리의 실제 실행은 모든 작업이 완료 될때까지 지연되므로 상태 출력을 서비스의 쉘 출력과 혼합하지 않음.
  • install 섹션에서 사용할 수 있는 옵션

    옵션내용
    Aliasunit에 대한 별칭
    RequiredByunit에 의존하는 unit 리스트
    WantedByunit에 약하게 의존하고 있는 unit 리스트
    Alsounit과 함께 설치 또는 제거될 unit 리스트 지정
    DefaultInstanceunit이 사용 가능한 기본 인스턴스를 지정


Amazon Linux 인스턴스에 shutdown script 추가

  • Amazon Linux는 Amazon Linux는 Fedora RHEL(Red Hat Enterprise Linux) 기반

    $ grep . /etc/*-release
    /etc/os-release:NAME="Amazon Linux AMI"
    /etc/os-release:VERSION="2017.03"
    /etc/os-release:ID="amzn"
    /etc/os-release:ID_LIKE="rhel fedora"
    /etc/os-release:VERSION_ID="2017.03"
    /etc/os-release:PRETTY_NAME="Amazon Linux AMI 2017.03"
    /etc/os-release:ANSI_COLOR="0;33"
    /etc/os-release:CPE_NAME="cpe:/o:amazon:linux:2017.03:ga"
    /etc/os-release:HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
    /etc/system-release:Amazon Linux AMI release 2017.03
    • RHEL은 systemd init 시스템을 사용.
      • 다른 init 시스템으로는 SysVinit 과 Upstart가 있음
      • systemd는 init 시스템 중에서 가장 복잡한 대신 뛰어난 유연성이 장점
      • 서비스의 시작 등 관련 기능을 제공하면서 소켓, 장치, 마운트포인트, 스왑영역, 다른 유닛 종류 등도 관리
    • 구버전에서는 systemctl 사용 불가능. chkconfig 명령 사용
  • RHEL 기반에서의 서비스 동작

    • 서비스 상태 : chkconfig --list
    • 서비스 시작 : service <서비스명> start
    • 부트 시 자동 시작 등록 : chkconfig <서비스명> on
  • Linux AMI에서는 systemctl을 사용할 수 없어서 chkconfig를 사용


chkconfig

chkconfig 등록

  • chkconfig 명령을 통해 서비스를 추가하려면 /etc/rc.d/init.d 디렉토리에 스크립트가 존재해야 한다.

    • 각 서비스마다 이 디렉토리에 스크립트를 하나씩 가지고 있다.
    • 서비스 중지용, 시작용 스크립트가 따로 있는 것이 아니라 init 데몬이 자신에게 어떤 파라미터를 전달하느냐에 따라 서비스를 중지하기도 하고 시작하기도 한다.
    • /etc/rc.d/init.d 디렉토리의 스크립트들은 서버의 특정 서비스를 시작하고 중지하기 위한 모든 것을 관장한다.
  • 해당 스크립트는 chkconfig를 위한 설정이 포함되어 있어야 한다.

    • httpd의 예

      # chkconfig: 2345 90 90# description: init file for Apache server daemon# processname: /usr/local/server/apache/bin/apachectl# config: /usr/local/server/apache/conf/httpd.conf# pidfile: /usr/local/server/apache/logs/httpd.pid
      • chkconfig의 앞 2345는 부팅레벨을 의미
      • 다음에 오는 90은 시작 우선 순위
      • 그 다음 90은 종료 우선 순위
      • 우선순위 값은 100이하의 수로, 숫자가 작을 수록 우선순위가 높다.
  • 아래 명령으로 chkconfig 등록

    $ chkconfig --add <파일명>

chkconfig on

  • script를 추하기 위해 systems unit file 사용

  • systemd의 주요 유닛으로는 service 유닛과 target 유닛이 있다.

    • service 유닛 : 리눅스 서버의 데몬을 관리하는데 사용
      • 파일명이 .service로 끝난다.
    • target 유닛 : 단순하게 다른 유닛을 일컫는 말
      • 파일명이 .target으로 끝난다.
  • 리눅스 시스템의 유닛 설정 파일은 /lib/systemd/system 디렉토리와 /etc/systemd/system 디렉토리에 존재

  • /etc/systemd/system의 하위에 .service 확장자를 가진 파일에 아래 내용 작성

    [Unit]
    Description=Run Scripts at Shutdown
    
    [Service]
    Type=oneshot
    RemainAfterExit=true
    ExecStart=/bin/true
    ExecStop=<스크립트 파일 경로>
    
    [Install]
    WantedBy=multi-user.target
  • chkconfig 명령을 통해 활성화

    $ chkconfig <서비스명> on

종료 script 수행 절차

  1. /etc/rc.d/init.d에 서비스로 등록할 스크립트 작성

    • 파일 권한은 755로 지정. chmod 755 <파일명>

    • 이 스크립트에 start, stop, restart 시의 동작을 정의한다.

      #!/bin/bash# chkconfig: 2345 90 30# description: shutdown file for filebeatstart() {
        touch /var/lock/subsys/shutdown-filebeat
        if [ !-d"/var/log/shutdown-filebeat" ];then
          mkdir /var/log/shutdown-filebeat
        fi
      }
      
      stop() {
        python3 /home/ec2-user/script/shutdown-filebeat.py
        rm -f /var/lock/subsys/shutdown-filebeat
      }
      
      restart() {
        stop
        start
      }
      
      case"$1"in
          start)
              start
          ;;
          stop)
              stop
          ;;
          restart)
              restart
          ;;
          *)
              echo$"Usage: $0 {start|stop|restart}"exit 1
      esac
      • 서비스 시작 시 shutdown-filebeat에 대한 로그를 기록할 디렉토리가 없는 경우 생성
      • 종료 시 python 스크립트를 수행
      • python 스크립트는 아래 스크립트 내용 설명 참조
  2. 서비스에 해당 스크립트 등록

    $ chkconfig --add <파일명>
  3. 서비스 등록 확인

    $ chkconfig --list
  4. /etc/systemd/system 하위에 스크립트 명과 동일한 이름의 .service파일 생성

    • /etc/rc.d/init.d의 스크립트와 한 쌍
    • /etc/rc.d/init.d의 스크립트, 즉 이 서비스를 관리하기 위한 설정파일이다.
  5. .service파일에 종료 시 실행할 스크립트를 지정

    [Unit]
    Description=Run Scripts at Shutdown
    
    [Service]
    Type=oneshot
    RemainAfterExit=true
    ExecStart=/bin/true
    ExecStop=<스크립트 파일 경로>
    
    [Install]
    WantedBy=multi-user.target
  6. chkconfig <서비스 명> on 명령을 통해 부트 시 자동 시작되도록 설정

    • 부트 시 위에서 설정한 스크립트의 start가 호출됨
  7. 여기서 시스템 종료를 하면 시작시 스크립트는 수행되는데 종료 시 스크립트는 수행되지 않는다.

    • /etc/rc3.d/ 하위에 종료시 stop 명령이 호출되도록 설정이 필요

    • 한가지 주의해야 할 점은 shutdown -r now를 통해 시스템을 종료하면 run level 6의 Reboot으로 수행된다. 그러므로 위에서 rc3.d에만 종료 링크를 걸어 주었기 때문에 제대로 스크립트가 실행되지 않는다.

    • 또한 시스템 종료에 대한 부분은 runlevel 0이기 때문에 rc0.d에도 포함되어야 한다.

      • /etc/rc0.d/와 /etc/rc6.d/ 하위에도 ln 명령을 통해 링크 파일을 만들어 주어 이를 해결
    • K<종료우선순위><서비스명>으로 심볼릭 링크를 만들어준다.

      • 톰캣의 종료 우선순위가 20이기 때문에 이보다는 나중에 종료 스크립트를 수행하도록 우선순위를 30으로 지정

      • 서비스명이 shutdown-filebeat라면 K30shutdown-filebeat로 생성

        $ ln -s ../init.d/shutdown-filebeat K30shutdown-filebeat
    • 이 때, 중요한 점은 filebeat보다 종료 스크립트가 먼저 수행되어야 한다는 것이다. 그래야만 filebeat가 보내던 파일을 도중에 중단하지 않고 종료 스크립트를 통해 대기를 할 수 있다.

      • filebeat의 종료 우선순위 조정. (종료 스크립트가 30이었으므로 filebeat의 종료 우선순위는 40으로 지정)

      • /etc/rc.d/init.d/filebeat 파일에서 종료 우선순위 변경

        #!/bin/bash## filebeat          filebeat shipper## chkconfig: 2345 98 40# description: Starts and stops a single filebeat instance on this system#
        ... 생략 ...
        • 주석의 chkconfig의 종료 우선순위를 40으로 설정
      • /etc/rc3.d/와 /etc/rc6.d/ 하위에 filebeat 관련 링크 추가

        sudo ln -s ../init.d/filebeat K40filebeat
    • 그리고 /etc/rc.d/init.d의 스크립트에서 start 구문에 /var/lock/subsys/<서비스명>으로 lock 파일을 생성해야 종료 시 스크립트를 수행할때까지 시스템이 종료되지 않고 락킹된다.

  8. 이제 시스템을 종료하게 되면 /etc/systemd/system/<서비스명>.service에 지정된 스크립트가 수행됨

filebeat 상태 체크를 위한 python 스크립트

import json
import sys
import time
from datetime import datetime

startDt = datetime.today()  #스크립트 시작 시간
updateDt = datetime.today()  #파일 변경 발생 시 갱신될 시간
files = {}


deflog(msg):
    f =open("/var/log/shutdown-filebeat/debug.log", 'a+')
    f.write("["+ datetime.now() +"] "+ msg +"\n")
    f.close()


log("filebeat shutdown check start.")

#파일이 갱신된지 1분이 될 동안 변경사항이 없는 경우 성공whileint((datetime.today() - updateDt).total_seconds()) <10:
    withopen('/var/lib/filebeat/registry') as data_file:
        data = json.load(data_file)

    for d in data:
        inode = d["FileStateOS"]["inode"]
        offset = d["offset"]

        if inode notin files:
            files[inode] = offset
            log("[add] inode : "+str(inode) +", offset : "+str(files[inode]) +" -> "+str(offset))
        else:
            if files[inode] < offset:  #존재 했었던 inode의 offset 값에 변동이 있었는지 검사
                log("[update] inode : "+str(inode) +", offset : "+str(files[inode]) +" -> "+str(offset))
                files[inode] = offset
                updateDt = datetime.today()  #변동이 있었다면 update 시간 초기화#총 진행 시간이 30분이 넘어가는 경우 실패ifint((datetime.today() - startDt).total_seconds()) >1800:
        log("filebeat shutdown fail. time out.")
        sys.exit(1)

    time.sleep(5)  # 5초 주기로 파일 체크

log("filebeat shutdown success.")
sys.exit(0)

EC2 인스턴스 Stop 시 종료 script를 다 끝마치지 않고 강제 종료되는 문제

참고


저작자 표시비영리변경 금지

[리뷰] 처음 배우는 머신러닝

$
0
0


 

 



책을 읽게 된 이유

얼마전까지만해도 머신러닝이라는 것은 저와는 완전히 동떨어진 기술이고, 관심은 가지만 알필요는 없을 것 같다는 생각을 가지고 있었습니다. 왜냐하면 머신러닝을 설명하는 글들을 보면 항상 복잡한 수학 공식이 적혀 있었고, 이 공식들을 사용해서 컴퓨터를 학습시켜 미래를 예측한다는 내용이었기 때문에 너무 어려워보이고 범접할 수 없는 느낌이 들었기 때문입니다. 하지만 불과 1,2년 사이에 먼 이야기 같았던 머신러닝이 점점 생활 속으로 들어오고 익숙한 단어가 되고, 주 마다 찾아가는 서점에서도 머신러닝, 딥러닝에 대한 책들이 점점 많아지는 것을 느꼈습니다. 그만큼 많은 사람들이 관심을 가지고 이에 대한 공부를 하고 있고, 제 주변에서도 관심을 가지고 살펴보는 사람들이 늘어가고 있었습니다.

최근에 회사에서 진행한 프로젝트와 주말마다 진행하는 스터디를 통해 데이터를 다루는 일이 많아지면서 이제는 머신러닝에 대해 한번 공부해보고 적용할 수 있었으면 좋겠다는 생각을 가지게 되었습니다. 그러면서 처음 머신러닝에 대한 개념을 잡기 위해 한빛미디어에서 출간한 처음 배우는 머신러닝이라는 책을 읽게 되었습니다. 처음 배우는 이라는 타이틀이 붙은 만큼 쉽게 쓰여져 있을 것이라 기대하고 읽기 시작하였습니다.

 


이 책을 읽으려면

이 책은 머신러닝을 처음 배우는 프로그래머나, 머신러닝 전공 희망자, 데이터 과학자를 대상으로 하기 때문에 입문자를 위한 책이기는 하지만 어느정도 프로그래밍에 대한 기초지식은 있어야 한다고 생각합니다. 실전 예제에 들어가기 전까지 이론적인 부분들은 프로그래밍 지식이 없이도 읽을 수 있지만 후반부에 실제로 실습을 하는 부분에서는 파이썬을 사용하여 코딩을 하고, 파이썬 문법에 대한 언급은 없으므로, 기본적인 지식이 있어야 따라해보며 이해해 나갈 수 있을 것입니다.


 

내가 책을 읽었던 방법

입문자용 책이었기 때문에 머신러닝의 개념들에 대한 설명이 깊이 있게 들어가지는 않고 추상적인 설명이 주를 이루고 있습니다. 아마도 깊게 들어가면 수학공식이 복잡하게 나올 것이기 때문에 저와 같은 입문자들에게는 적절한 난이도라고 생각합니다. 하지만 쉽게 쓰여진 이 개념들도 종류가 너무 많다보니 머릿속에 정리가 잘 되지는 않았습니다. 수학 공식이 등장하는 부분은 대부분 이런게 있구나 하고 넘어갔고, 개념적인 설명이 있는 부분은 정독을 하며 최대한 이해해보려고 노력하며 읽어내려갔습니다. 하지만 이 또한 두세번정도 읽어도 이해가 안되면 그냥 넘어갔습니다. 머신러닝은 여러번의 시행착오를 거쳐가며 개선해나가는 과정을 통해 익숙해지고 이해가 되기 때문에 너무 이론적인 부분에서 막혀 있을 필요는 없을 것 같다는 생각이었습니다. 수학 공식 또한 이 공식이 어떠한 곳에 사용되고 왜 사용해야하는지 정도만 이해하면 어차피 검증된 라이브러리들이 잘 구현되어 있기 때문에 적절한 곳에 가져다 쓰면 된다고 생각하여 그정도 까지만 이해하고 넘어갔습니다.


 

책을 읽으며 좋았던 점

9장까지 이론적인 내용들을 읽고나면 이제 실제로 코딩을 해볼 수 있는 실전 예제들이 등장합니다. 저는 이론적인 부분은 난해하고 조금 지겨움을 느꼈었는데 실전 예제를 직접 따라해보고 실제 결과를 눈으로 확인하니 큰 재미를 느꼈습니다. 그리고 이전에 이해가 잘 안되던 부분도 어느정도 이해가 되면서 실제 업무에 적용할 수 있을만한 요소들에 대한 인사이트를 얻을 수 있었습니다. 저는 이 과정에서 재미와 경험, 인사이트를 얻을 수 있었기 때문에 이론적인 부분을 스킵하더라도 실전 예제는 꼭 직접 해보실 것을 추천합니다. 조금씩 다른 유형의 실전 예제들이 4가지나 수록이 되어 있기 때문에 전부 다 따라해본다면 이 책에서 설명하고 있는 이론적인 부분들 또한 함께 이해가 될 것이라 생각됩니다.

 

마무리

이 책을 읽고나서 머신러닝이라는 다가가기 힘들었던 기술에 대해 어느정도 감을 잡고, 예제를 따라해보며 더 해보고 싶어지는 재미와 나도 머신러닝을 해볼 수 있겠다는 자신감을 가질 수 있게 되어 만족스러웠습니다. 이 책의 추상적인 이론에서 조금 더 자세히 들여다 보고 싶은 분들은 유투브에서 김성훈님의 모두를 위한 딥러닝 강좌를 보실 것을 추천드립니다.

저작자 표시비영리변경 금지

로그스태시는 장애 시 어떻게 데이터 손실을 방지할까?

$
0
0

로그스태시는 엘라스틱 스택에서 데이터를 수집하고 가공하여 엘라스틱 서치로 전송하는 역할을 담당하고 있습니다. 이 과정은 입력,필터,출력 플러그인을 통해 하나의 파이프라인을 형성하며 이루어지는데 이 처리 과정 중에 장애가 발생하여 로그스태시가 종료되면 처리중인 데이터는 손실됩니다. 이러한 손실을 방지하기 위해 로그스태시는 어떠한 노력을 하고 있을까요?


로그스태시는 유입된 이벤트를 처리할 때 출력이 완료되어야만 해당 이벤트가 완료된 것으로 판단하고, 그 전에는 큐에 이벤트 레코드를 유지합니다. 로그스태시를 Ctrl+C 또는 SIGTERM 신호를 통해 정상 종료할 경우에는 데이터 수집을 중지하고, 필터와 출력 플러그인에 의해 처리 중인 이벤트들을 정상적으로 처리 완료한 후에 종료합니다. 기본적으로 이 이벤트들이 저장되는 큐는 메모리상에 저장이 되지만 설정에 의해 디스크에 저장(Persistent Queue)되도록 변경할 수 있습니다. 메모리에 기록할 경우에는 로그스태시에 장애가 발생하면 데이터가 손실되기 때문에 디스크에 저장할 것을 권장하고 있습니다.

로그스태시가 비정상적으로 종료되는 경우에는 처리되지 않은 이벤트들은 Persistent Queue(이하 PQ)를 설정한 경우 디스크에 기록되어 로그스태시가 다시 시작되면 디스크에서 이벤트 정보를 읽어와서 처리되지 않은 이벤트들을 이어서 처리하게 됩니다.

PQ는 로그스태시 5.1 버전부터 지원하기 시작했는데 비정상적인 오류가 발생할 경우 데이터 손실을 방지하고 At-Least-Once delivery(최소 한번 배달) 보장을 제공하기 위해 디자인 되었습니다. 이는 데이터 복원 과정 중 중복 데이터가 발생할 수는 있지만 데이터가 손실되는 일은 없도록 하는 것을 의미합니다.

PQ는 이벤트가 파이프라인을 통해 처리 될 때 입력과 필터 플러그인 사이에서 동작하여 아직 처리되지 않은 이벤트로 큐에 저장합니다. 이 후 출력 플러그인을 통해 데이터 전달하고 처리가 완전히 완료되면 이벤트 처리가 완료된 것으로 큐에 기록됩니다(상태값이 ACK로 변경됨). 디스크 저장으로 인해 PQ를 사용하면 성능에 영향이 있기 때문에, 속도와 내구성 사이의 트레이드 오프가 발생합니다. 또한 이벤트가 저장될 파일의 최대 크기(기본값 1GB)를 넘어서면 로그스태시로의 데이터 유입을 막고 여유 공간을 확보할 때까지 대기하게 되므로 주의해야합니다.

기본적으로 수신된 이벤트가 1024개가 될 때마다 디스크에 작성(queue.checkpoint.writes 설정)하여 데이터 손실을 방지하기 때문에 1024개의 이벤트가 도달되지 않은 채로 로그스태시가 종료되면 데이터가 손실될 수 있습니다. queue.checkpoint.writes 설정 값을 1로 설정하는 경우 이벤트가 발생할 때마다 디스크에 작성하게 되기 때문에 내구성은 올라가겠지만 성능에 막대한 영향을 끼치게 됩니다. 또한 OS 레벨에서 크래시가 발생할 경우에도 디스크에 안전하게 기록되지 않은 데이터는 손실 될 수 있습니다. 이러한 손실까지 방지하고자 하는 경우 디스크를 RAID 구성과 같은 복제 기술을 사용해야 합니다. (하드웨어적인 문제까지 로그스태시가 대응하지는 못함)

큐에 저장된 이벤트들은 디스크 상에서 페이지라는 단위로 관리하게 되는데 하나의 페이지에는 여러개의 이벤트들이 포함되어 있습니다. 해당 페이지에 속한 이벤트들이 전부 처리가 완료된 상태(ACK)가 되면 디스크 가비지 콜렉션에 의해서 해당 페이지가 삭제됩니다. 만일 페이지 내에 이벤트들 중 하나라도 처리가 완료되지 않은 경우에는 해당 페이지가 디스크에 유지됩니다.

Elastic 블로그에 따르면 AWS EC2 c3.4xlarge 인스턴스에서 로그스태시 5.4.1 버전으로 in-memory 큐와 PQ의 성능을 벤치 마크한 결과 in-memory에 비해 10%의 성능 저하가 발생하였는데, 이 수치는 테스트한 환경에 따라 달라질 수 있습니다. In-memory 큐를 사용한 경우 초당 약 10600개의 이벤트가 발생하고, PQ를 사용한 경우 초당 약 9500개의 이벤트가 발생하였습니다.

개인적인 생각으로는 대부분의 경우에는 PQ를 사용하고, in-memory를 사용해야 한다면 데이터를 생성하는 응용프로그램에서 Logstash와 병행하여 별도의 저장소에 데이터를 전달하여 언제든 복원이 가능한 환경을 구성하는 것이 좋을 것이라 생각합니다.


참고


저작자 표시비영리변경 금지

Amazon Elasticsearch에서 로컬 Elasticsearch로 데이터 이전하기 (Snapshot)

$
0
0

현재 프로덕션 환경에서 Amazon Elasticsearch Service를 사용 중이었는데 물리적인 부분을 AWS에서 관리해주는 장점도 있는 반면 비용적인 부분이나 제약사항들 때문에 불편한 부분들이 있었다. 그래서 EC2 인스턴스에 직접 구성해볼까 고민하던 차에 이번에 Elastic Stack이 버전업이 된 것을 계기로 이전을 해보기로 결심했다. 가장 문제되는 부분이 현재 쌓인 데이터를 어떻게 문제 없이 옮길까 하는 것이었는데 현재 몽고디비에 이중으로 데이터를 보관하고 있었기 때문에 몽고디비에 쌓인 데이터를 bulk insert를 사용하여 재 색인을 하려고 하였는데 시간이 엄청나게 소요되었다. 그래서 스냅샷 기능을 활용해보기로 하였고, 결과적으로 매우 빠르게 데이터를 옮길 수 있었다.

Amazon Elasticsearch에서 snapshot을 생성하기 위해서는 먼저 Elasticsearch 서비스와 S3에 접근 할 수 있는 IAM Role이 필요하다. 역할(Role)을 생성할 때 아래의 페이지에서 신뢰할 수 있는 유형의 개체를 선택해야 하는데 현재 Elasticsearch가 존재하지 않기 때문에 EC2를 선택하여 생성하도록 한다.

그리고나서 정책(Policy) 생성 버튼을 클릭하고 아래 JSON 문자열을 직접 입력한다. 여기서는 버켓 이름을 hive-es-index-backups로 생성했다.

{
    "Version":"2012-10-17",
    "Statement":[
        {
            "Action":[
                "s3:ListBucket"
            ],
            "Effect":"Allow",
            "Resource":[
                "arn:aws:s3:::hive-es-index-backups"
            ]
        },
        {
            "Action":[
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "iam:PassRole"
            ],
            "Effect":"Allow",
            "Resource":[
                "arn:aws:s3:::hive-es-index-backups/*"
            ]
        }
    ]
}

생성이 완료되면 역할 목록에서 방금 생성한 역할을 선택한 후 신뢰 관계 편집을 선택하여 ec2로 설정되어 있는 부분을 아래와 같이 es로 변경한다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "es.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

IAM 설정이 완료되었으므로 이제는 snapshot을 어떠한 방식으로 저장할지를 elasticsearch 쪽에 지정하는 snapshot repository 생성 절차가 필요하다. 이를 위해 먼저 repository를 생성하는 파이썬 스크립트를 작성한 후 수행한다. (IAM 설정과 파이썬 스크립트는 AWS 백서에 잘 나와있다.)

from boto.connection import AWSAuthConnection


classESConnection(AWSAuthConnection):
    def__init__(self, region, **kwargs):
        super(ESConnection, self).__init__(**kwargs)
        self._set_auth_region_name(region)
        self._set_auth_service_name("es")

    def_required_auth_capability(self):
        return ['hmac-v4']


if__name__=="__main__":
    client = ESConnection(
        region='ap-northeast-2',
        host='search-xxx.ap-northeast-2.es.amazonaws.com',
        aws_access_key_id='<ACCESS_KEY>',
        aws_secret_access_key='<SECRET_KEY>', is_secure=False)

    print('Registering Snapshot Repository')
    resp = client.make_request(method='POST',
                               path='/_snapshot/hive-es-backup',
                               data='{"type": "s3","settings": { "bucket": "hive-es-index-backups","region": "ap-northeast-2","role_arn": "arn:aws:iam::<ACCOUNTID>:role/ESSnapshotRole"}}')
    body = resp.read()
    print(body)

client.make_request 함수의 인자로 repository명과 repository에 대한 설정을 지정한 후 요청하면 해당 내용으로 elasticsearch에 repository가 생성된다.

kibana의 Dev Tools를 사용하여 아래 명령을 수행해보자.

GET _snapshot?pretty

그러면 아래와 같이 생성된 repository정보를 확인할 수 있다.

{ "cs-automated": { "type": "s3" }, "hive-es-backup": { "type": "s3", "settings": { "bucket": "hive-es-index-backups", "region": "ap-northeast-2", "role_arn": "arn:aws:iam::<ACCOUNTID>:role/<ROLE_NAME>" } } }

이제 실제로 스냅샷을 생성해야하는데 여기서는 1월 1일에 생성된 인덱스인 hive_live_2018_01_01 인덱스를 색인하도록 한다. 완료될 때까지 기다리려고 wait_for_completion 설정을 true로 지정하였는데 이것도 내부적으로 timeout 시간이 있는지 기다리가다 Fail 오류가 발생한다.

PUT _snapshot/hive-es-backup/hive_live_2018_01_01?wait_for_completion=true
{
  "indices": "hive_live_2018_01_01",
  "ignore_unavailable": true,
  "include_global_state": false
}

스냅샷이 정상적으로 되었는지 확인하려면 아래 명령을 수행한다. (특정 스냅샷만 보려는 경우 _all 부분을 snapshot 명으로 입력한다.)

GET _snapshot/hive-es-backup/_all?pretty

하지만 snapshot 상태 정보를 확인(GET /_snapshot/hive-es-backup/hive_live_2018_01_01)해보면 IN_PROGRESS 상태인 걸보니 내부적으로는 진행 중인 듯 하다.

{
  "snapshots": [
    {
      "snapshot": "hive_live_2018_01_01",
      "uuid": "_ecORIa8RteCruw54pDzCA",
      "version_id": 5050299,
      "version": "5.5.2",
      "indices": [
        "hive_live_2018_01_01"
      ],
      "state": "IN_PROGRESS",
      "start_time": "2018-01-18T01:48:39.244Z",
      "start_time_in_millis": 1516240119244,
      "end_time": "1970-01-01T00:00:00.000Z",
      "end_time_in_millis": 0,
      "duration_in_millis": -1516240119244,
      "failures": [],
      "shards": {
        "total": 0,
        "failed": 0,
        "successful": 0
      }
    }
  ]
}

잠시 기다린 후 다시 상태 정보를 확인해보면 아래와 같이 SUCCESS 상태로 전환된 것을 확인할 수 있다.

{
  "snapshots": [
    {
      "snapshot": "hive_live_2018_01_01",
      "uuid": "_ecORIa8RteCruw54pDzCA",
      "version_id": 5050299,
      "version": "5.5.2",
      "indices": [
        "hive_live_2018_01_01"
      ],
      "state": "SUCCESS",
      "start_time": "2018-01-18T01:48:39.244Z",
      "start_time_in_millis": 1516240119244,
      "end_time": "2018-01-18T01:53:11.247Z",
      "end_time_in_millis": 1516240391247,
      "duration_in_millis": 272003,
      "failures": [],
      "shards": {
        "total": 5,
        "failed": 0,
        "successful": 5
      }
    }
  ]
}

완료된 스냅샷을 로컬 엘라스틱서치에서 복원하기 위해서는 로컬 엘라스틱서치에도 마찬가지로 S3로 snapshot을 생성(이 때는 readonly로 설정하는 것이 좋음) 해야하는데 S3에 접근하기 위해서는 repository-s3 플러그인이 설치되어 있어야 한다.

$ ./elasticsearch-plugin install repository-s3

다음으로 AWS 서비스에 접근하기 위한 access key와 secret key에 대한 설정이 필요한데 이는 elasticsearch-keystore를 통해 등록이 가능하다. list 명령을 통해 keystore가 존재하는지 확인해보고, 존재하지 않을 경우에는 생성한다.

$ bin/elasticsearch-keystore list
ERROR: Elasticsearch keystore not found. Use 'create'command to create one.
$ bin/elasticsearch-keystore create
Created elasticsearch keystore in /home/ubuntu/programs/elasticsearch-6.1.2/config

access/secret키를 아래 명령을 통해 입력하도록 한다.

$ ./elasticsearch-keystore add s3.client.default.access_key
$ ./elasticsearch-keystore add s3.client.default.secret_key

이제 로컬 키바나를 통해(curl 명령을 사용해도 되지만 편의상 키바나를 사용했다.) elasticsearch로 동일한 repository(S3 버켓)를 생성하도록 한다.

PUT _snapshot/hive-es-backup
{
  "type": "s3",
  "settings": {
    "bucket": "hive-es-index-backups",
    "region": "ap-northeast-2"
  }
}

이제 S3에 저장된 스냅샷을 아래 명령을 통해 복원해보도록 하자.

POST /_snapshot/hive-es-backup/hive_live_2018_01_01/_restore
{
  "indices": "hive_live_2018_01_01"
}

그러면 순식간에 응답을 받게되는데 복원이 끝난 것을 의미하지는 않기 때문에 인덱스 상태를 확인하며 정상적으로 색인이 될 때까지 기다려야 한다. 아래 명령을 수행해보면 현재 인덱스의 상태를 확인할 수 있다.

GET /_cat/indices?v&s=index

restore 시에는 인덱스 설정이 레플리카 수는 1개, flush 주기는 1초 등 기본 값으로 설정이 되어있다. 이를 아래와 같이 변경하여 색인 성능을 높일 수도 있다.

POST /_snapshot/hive-es-backup/hive_live_2018_01_01/_restore
{
  "indices": "hive_live_2018_01_01",
  "index_settings": {
    "index.number_of_replicas": 0,
    "index.refresh_interval": -1
  }
}

결과를 확인해보면 복원을 수행한 직후에는 아래와 같이 document 수 조차도 계산되지 않고 인덱스만 생성되어 있고, 정상적으로 색인이 되어있는 .kibana는 health 상태가 green인 것과 달리 방금 복원을 요청했던 hive_live_2018_01_01 인덱스의 health 상태가 yellow인 것을 확인할 수가 있다.

health status index                uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   hive_live_2018_01_17 B3tGrOPJRt2PaTp65g66-A   5   1

잠시 시간이 지난 후에는 document 수와 용량은 확인되지만 아직까지는 health 상태가 yellow이다.

health status index                             uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .kibana                           SFYFvaq3RrmyjcJ1pipBYw   1   1          2            0    156.4kb         78.2kb
yellow open   hive_live_2018_01_01              uLbBcPPrRoOxqWi-lgebag   5   1    4169704            0      6.7gb          6.7gb

green이 될 때까지 기다리면 복원이 완료된 것이다. 이 때 스냅샷을 생성한 엘라스틱서치의 document 개수와 복원한 엘라스틱서치의 document 개수를 꼭 확인해보도록 하자.

[리뷰] 스프링4 입문

$
0
0


책을 읽게 된 계기

진행 중이던 프로젝트가 하나 끝나고, 다음 프로젝트를 준비하면서 스프링에 대해 공부를 하게 되었다. 모바일 게임의 웹 서버 프로젝트이다 보니 스프링 프레임워크까지 쓰는 것에 대해 대부분 반감을 가지고 있어서 이전에는 서블릿 기반으로 간단하게 구현을 해서 사용을 했었다. 나 또한 스프링 프레임워크를 도입 해야만 하는 이유가 딱히 없었기 때문에 서블릿을 사용하며 필요한 부분만 구현하는 식으로 프로젝트를 진행했었기 때문에 따로 공부할 것이 많지 않아서 편한 부분은 있었다. 하지만 자바 웹 서버 개발을 하는 사람들이 하나같이 스프링을 극찬하며 많이 사용하는 이유가 있을거라는 생각에 스프링 공부를 한번 해보기로 마음 먹었다. 공부를 해나가면서도 스프링이 좋은 건 알겠는데 굳이 우리 프로젝트에서 사용해야할 이유가 떠오르지 않았고 팀원들을 설득시킬 만큼의 이점이 없어 보였다.


책을 읽으며 느낀점

그러던 중 스프링4 입문 책을 읽으며 1장에서 이러한 의문들을 해소할 수가 있었다. 1장의 내용은 스프링이 나온 배경과 어떻게 발전해왔는지에서부터 스프링을 사용했을 때의 이점과 스프링이 추구하는 것이 무엇인지를 알게되니 그동안 고민하고 의문이 들었던 부분들이 하나씩 해소가 되는 것을 느꼈다. 곧바로 스프링에 대한 학습을 시작하지 않고, 독자들에게 스프링을 왜 사용해야 하는지에 대한 이유를 먼저 알려주니 얼른 다음 장이 읽고 싶어졌다.


스프링에 대한 모든 내용을 담기에는 너무 방대하기 때문에 이 책에서는 웹 서버 개발을 위한 스프링 MVC에 초점이 맞춰져 있었다. 하지만 스프링의 핵심 개념인 DI와 AOP에 대해 자세히 설명하고 기반 지식들을 알기 쉽게 설명하고 있기 때문에 이 책을 온전히 이해하고 난 뒤라면 스프링의 다른 부분들도 쉽게 이해할 수 있을 것이라는 생각이 들었다. 개인적인 생각이지만 일본인 저자의 책들은 문장의 흐름이 자연스럽고, 문단 구성도 잘 되어 있어서 내용을 이해하는데 큰 도움이 되는 것 같다. 그림은 많지는 않지만 읽기 쉽기 때문에 재미있게 책을 읽어나갈 수 있었다.


역시나 가장 큰 장애물은 스프링을 사용하기 위한 환경 설정이었다. 예제를 따라하기 위해 STS를 설치하고 개발 환경을 구성하는데 시간이 많이 소요되었었고, 어노테이션을 많이 사용하기 때문에 중간에 하나씩 빼먹는 것에서 오류가 나고, 이러한 오류는 또 찾기도 힘들었었다. 스프링 부트를 사용하면 이러한 설정에 대한 어려움을 덜어낼 수 있지만 책의 후반부에 스프링 부트가 등장하기 때문에 환경 설정은 피할 수 없다. 하지만 개인적으로는 너무 편한 것을 먼저 사용하는 것보다는 정석대로 하나씩 설정을 배워가며 돌아가는 원리를 파악한 후에 이러한 것들을 자동으로 해주는 편리한 프레임워크를 사용하는 것이 더 좋다고 생각한다. 저자도 그러한 이유 때문에 스프링 부트를 후반부에 넣지 않았을까


마치며

스프링에 대한 기반 지식을 탄탄이 하는데는 강력 추천 할만한 책이지만 스프링 5가 릴리즈 된 상황에서 스프링 4 책이 출판된 것이 조금 아쉬웠다. 그래도 버전에 상관 없이 기반을 다질 수 있는 책이기 때문에 큰 도움을 주는 책이다. 다음 프로젝트에서 스프링을 사용할지는 아직 모르지만 스프링을 공부하다보면 프로그래밍에 대한 실력도 향상되는 느낌이 들었다. 주어진 틀 안에서만 코딩하는 개발자가 아닌 원리를 파악하고, 제대로 코딩하고 싶은 개발자들에게 추천!

[AWS] Athena 테이블 파티셔닝

$
0
0

Amazon Athena 테이블 파티셔닝

아테나에서 테이블 파티셔닝 하는 방법은 두가지가 있다. 첫번째는 S3 버킷명을 아테나에서 파티셔닝 가능하도록 지정한 경우 자동으로 매핑되도록 하는 방법이고, 두번째는 그렇지 않은 경우 수동으로 일자에 해당하는 버킷은 연결하도록 지정하는 방법이다.


버킷명으로 자동 매핑

먼저 첫번째 방법으로 자동 매핑이 가능하도록 하려면 아래와 같은 형식의 버킷명 하위에 파일들이 위치해야한다.

s3://yourBucket/pathToTable/<PARTITION_COLUMN_NAME>=<VALUE>/<PARTITION_COLUMN_NAME>=<VALUE>/

예를 들면 아래와 같은 형식이다.

s3://hive-live-log/DEBUG/year=2018/month=03/day=05/
혹은 
s3://hive-live-log/DEBUG/dt=2018-03-05/

이렇게 버킷을 생성하고 아테나에서 테이블 생성 시 파티션 컬럼을 설정하는 부분에서 아래와 같이 파티션 명에 맞춰서 컬럼을 생성한다.


테이블이 생성되고 나면 자동으로 파티션을 지정할 수 있도록 아래 명령을 수행한다. 여기서는 테이블명을 debug_partitioned로 생성했다.

MSCK REPAIR TABLE debug_partitioned;

그러면 약간의 시간이 흐른 뒤에 아래와 같은 결과가 반환 된다.

debug_partitioned:year=2018/month=03/day=05
Repair: Added partition to metastore debug_partitioned:year=2018/month=03/day=05


수동 매핑

만약 버킷명이 위와같이 생성되어 있지 않은 경우에는 어쩔 수 없이 ALTER TABLE 명령으로 수동 매핑을 해주어야 한다. 아래와 같은 구조로 버킷이 지정되어 있다고 가정해보자.

s3://hive-live-log/DEBUG/2018/03/05/

이런 경우 아테나 테이블의 파티션 컬럼과 매핑이 되지 않기 때문에 아래와 같은 쿼리를 통해 일자별로 파티션 등록을 해주어야 한다.

Alter Table <tablename> add Partition (PARTITION_COLUMN_NAME = <VALUE>, PARTITION_COLUMN2_NAME = <VALUE>) LOCATION ‘s3://yourBucket/pathToTable/YYYY/MM/DD/

예를 들면 아래와 같다.

Alter Table debug_partitioned add Partition (year='2018', month='03', day='05') LOCATION 's3://hive-live-log/DEBUG/2018/03/05/'


정리

이렇게 파티셔닝 기능을 사용하여 테이블을 구성하면 쿼리당 스캔되는 데이터 양을 줄일 수 있기 때문에 성능을 향상 시킬 수 있다. 이 기능을 몰랐을 때는 S3 버킷의 범위별로 테이블을 하나씩 생성해서 테이블이 굉장히 많아졌었는데 단일 테이블로 사용할 수 있어서 편리했다. 나의 경우에는 초기에 파티셔닝 기능을 염두하고 버킷을 생성하지 않았기 때문에 수동 매핑 방식을 사용하였는데 일자가 변경될 때마다 ALTER TABLE 명령을 수행해야한다는 불편함이 존재하긴 했지만 자동 스크립트를 통해 자동화 할 수 있었다.


참고


[리뷰] 9가지 사례로 익히는 고급 스파크 분석(2판)

$
0
0

들어가기전에

이전 프로젝트에서 엘라스틱서치를 통해서 데이터 분석에 대한 경험을 해볼 수가 있었고, 중요성에 대해서 알 수 있게 되었었습니다. 데이터를 직접 분석해보고 이를 시각화 해보는 과정에서 기존에는 인지하지 못했던 여러 정보들을 얻을 수 있고, 이를 통해 서비스를 개선할 수 있는 다양한 아이디어가 떠오르는 것을 경험해볼 수도 있었습니다. 왜 많은 회사들이 데이터를 다루는 것을 중요하게 생각하고, 이를 위해 어마어마한 투자를 하고 있는지 알 것 같았습니다. 데이터를 분석하는 방법으로는 제가 사용해보았던 엘라스틱서치를 사용할 수도 있고, R이나 스파크 등 다양한 툴들이 존재합니다. 제가 느꼈던 데이터 분석을 위한 툴들의 공통점은 처음 진입하기가 너무 어렵게 느껴진다는 것이었습니다. 머신러닝의 경우에는 내가 감히 접근해도 되는 분야인가 하는 생각이 들 정도로 어려워보였습니다.




책의 느낌

9가지 사례로 익히는 고급 스파크 분석이라는 책을 처음 펼쳐보았을 때도 같은 생각이 들었습니다. 먼저 간단하게 훑어보니 이론적인 설명은 아주 짧게 되어 있고, 책 제목처럼 사례들을 중심으로 되어있었는데 각각의 사례들이 쉽지 않아보였습니다. 그래서 일단은 뒷 내용은 제쳐두고, 앞의 내용을 숙지하자는 생각으로 설명을 읽어가며 명령어들을 하나씩 따라해보았습니다. 스파크에 대한 이론적인 부분에 대한 비중이 적긴 하지만 필요한 내용들에 대해 간단 명료하게 작성되어 있기 때문에 나머지 부수적인 내용은 활용에 대한 부분들이라 필요한 경우에 인터넷을 찾아가며 해도 무관해보였습니다. 엘라스틱서치를 공부할 때도 두꺼운 책을 세세하게 읽어나가는 것보다 조금이라도 빨리 실전 예제를 해보면서 잘 안되는 부분들이나 필요한 부분들을 검색해가며 공부를 했던 것이 더 효과적이었습니다. 예제 또한 너무 동떨어진 내용이 아니고 실생활에서 접할 수 있는 주제들이라서 조금 더 재미있게 따라해볼 수 있었습니다.



스파크에 대해서는 이름만 아는 수준이었는데, 책을 읽다보니 엘라스틱서치와 같이 집계를 수행할 수 있는 기능도 제공하고, 머신러닝도 수행할 수 있는 다양한 기능을 제공한다는 것을 알게되었습니다. 사실 따라하는데에 급급해서 이 책의 모든 내용을 이해하기는 힘들었습니다. 하지만 중요한 것은 스파크를 통해 이러한 일들을 할 수가 있고, 필요한 경우 도입을 검토해볼 수 있겠다는 생각을 갖게 되었습니다.


이 책을 통해 누구나 스파크를 시작해볼 수 있겠지만 모든 사람들이 이 책을 이해하기는 힘들 것 같다는 생각이 들었습니다. 개인적으로 이 책은 스파크에 대한 감을 익히는데 좋지만, 입문자가 이해하기는 어렵기 때문에 스파크를 공부해나가며 이 책에 수록된 예제들을 하나하나 이해해나간다면 이 책을 전부 이해했을 때는 스파크에 대해 어느정도 통달한 경지가 되지않을까하는 생각이 들었습니다.



맺음말
결론적으로 책의 구성은 나쁘지 않았고, 아직은 저에게 어려운 내용이지만 차차 정복해나가는 재미가 있을 것 같다는 생각이 들었습니다. 이 책에 수록된 내용 외에도 스파크를 활용하는데 필요한 지식들이 더 많이 존재하기 때문에 여러 다른 책들과 검색을 통해 지식을 습득하는 것이 좋을 것 같습니다.






TCP/IP 스택의 계층 구조, 멀티플레이어 게임 프로그래밍 책 정리

$
0
0

해당 내용은 길벗출판사 멀티플레이어 게임 프로그래밍도서에서 일부 발췌하였습니다.



패킷 스위칭

  • 지리적으로 떨어져 설치된 컴퓨팅 자원에 서로 다른 장소에서 일하는 과학자가 접근하기 위한 연결 수단이 필요
  • 그 전까지는 장거리 통신에서 서킷 스위칭(circuit switching) 사용
    • 송수신 단말 사이에 회로(circuit) 연결을 해두고 정보 전달 수행
    • 회로보다 작은 단위인 회선(line)을 길게 짜 맞추어 연결한 것
    • 송수신이 일어나는 동안 연결 유지. 전용선
    • 회선은 모든 송수신이 끝날 때까지 그 연결 전용으로만 사용해야 함.
    • 통신이 끝나면 회선 사이의 연결을 모두 끊은 후 다른 정보를 송수신하기 위해 각각 다른 회선과 다시 연결.
    • 가용성 면에서 제한적
  • 패킷 스위칭은 하나의 송수신에 회선을 전용으로 할당해야 할 필요가 없으므로 가용성을 높일 수 있다.
    • 회선 자체는 공유하되, 송수신 내용을 패킷이라는 작은 뭉치로 나눈 뒤 저장 후 전달(store and forward) 절차를 사용
    • 네트워크의 각 노드는 같은 네트워크의 여러 노드에 연결되고, 연결된 회선으로 노드 사이에 패킷을 주고 받을 수 있다.
    • 각각의 노드는 수신한 패킷을 저장하고 이후 목적지에 가까운 다른 노드로 이를 전달
    • 서킷 스위칭과 비교해 가장 중요한 차이점은 같은 회선을 이용해 여러 노드로의 송수신이 동시에 진행될 수 있다는 점.
    • 한번에 많은 송수신 패킷을 처리할 수 있으므로 가용성 증대.
  • 패킷 스위칭 자체는 추상화된 개념.
  • 구체화 하기 위해 네트워크의 각 노드가 어떻게 데이터 패킷을 꾸릴지, 어떻게 패킷을 네트워크를 통해 보낼지를 정형화해 둔 프로토콜이 필요
  • 이렇게 발전한 프로토콜을 통칭해 TCP/IP 스택 또는 TCP/IP Suite라고 한다.


TCP/IP 스택의 계층 구조

  • 목적에 따라 여러 프로토콜을 갈아 끼울 수 있게 계층을 추상화하여 나누고, 각 계층이 저마다의 소임에 충실할 수 있게끔 설계하여 각기 독립적인 계층이 다른 계층을 뒷바침하고 데이터를 적절히 연계할 수 있다.
  • 우아하게만 보이는 TCP/IP 스택에도 여기저기 땜질한 자국도 많이 보이는데 프로토콜 작성자마다 성능이니 확장성이니 하는 핑계로 쓸모있긴 하지만 설계 철학에 반하는 복잡한 예외사항으로 범벅을 해두었다.
  • 게임 제작에는 주로 TCP/IP의 상위 계층을 주로 다룸
    • 최적화를 위해서는 하위 계층이 어떻게 동작하는지, 상위 계층과는 어떤 식으로 상호작용하는지 알아두는 것이 좋다.
  • OSI 7계층 중 게임 개발과 관련이 있는 물리/링크/네트워크/전송/응용 계층에 대해 살펴본다.
  • 각 계층은 저마다 자기 윗단 계층을 지원하기 위해 수행해야 하는 역할이 있다.
    1. 윗단 계층에서 데이터 블록을 수신
    2. 계층 헤더를 추가해 패킷을 꾸린다
    3. 데이터를 아랫단 계층으로 전달해 송신 과정을 계속해 나간다.
    4. 아랫단 계층에서 수신된 데이터를 받는다.
    5. 헤더를 제거하여 수신된 데이터의 패킷을 푼다.
    6. 수신된 데이터를 윗단 계층으로 전달해 수신처리를 계속해 나간다.
  • 객체지향에 비유하자면 계층은 인터페이스, 각 프로토콜이나 프로토콜 집합은 그 인터페이스를 구체화한 구현물.
  • 각 계층마다 헤더를 가지고 있고 층을 거쳐갈 수록 헤더를 붙이거나 제거하는 식으로 전달됨.


물리 계층

  • 가장 기본적인 하드웨어 전송을 지원
  • 네트워크로 연결된 컴퓨터, 즉 호스트 사이의 물리적 연결을 책임짐
  • 물리적으로 연결된 매체가 있어야 정보 전달이 가능
    • 전화선, 동축케이블, 광섬유케이블 등
    • 핸드폰, 노트북과 같은 전파를 사용한 정보 전달도 포함


링크 계층

  • 전자기학을 벗어나 컴퓨터학이 본격적으로 적용되는 곳

  • 송신 호스트가 정보를 꾸려 물리 계층을 통해 정보를 보낼 수 있는 수단, 그리고 수신 호스트가 높은 확률로 그 정보를 수신하여 안에 담긴 정보를 꺼낼 수 있게 하는 수단을 제공

  • 링크 계층의 송수신 단위를 프레임(frame)이라고 함.

  • 링크 계층의 역할

    • 특정 목적지에 주소를 부여해서 각 프레임에 기재토록 하여 호스트를 식별할 수단 제공
    • 수신 측 주소와 데이터를 담을 수 있는 프레임 포맷 정의
    • 한 번에 데이터를 얼마까지 보낼 수 있는지 윗단 계층에서 알 수 있게끔 프레임의 최대 길이를 정의
    • 물리 계층을 거쳐 전달된 신호를 의도된 호스트가 수신할 수 있게 프레임을 물리적인 전기 신호로 변환하는 방법 정의
  • 의도된 호스트에 프레임이 전달될지 아닐지는 확률적으로 결정되며 항상 보장되는 것은 아니라는 점에 유의

  • 링크 계층에서는 프레임이 도착하였는지 확인하거나 실패하였을 때 다시 보내는 등의 시도를 전혀 하지 않는다.

    • 이러한 이유로 링크 계층을 비신뢰성(unreliable) 통신이라 함.
  • 물리 계층을 구현하고자 하는 물리적 연결 매체마다 대응되는 하나 이상의 프로토콜이 링크 계층에 존재

    • 랜선 연결은 1000BASE-T 같은 이더넷 계열 프로토콜로 통신

    • 전파 연결은 와이파이 프로토콜 또는 장거리 무선 프로토콜인 3G나 4G로 통신

  • 링크 계층의 구현물과 물리 계층의 연결 매체가 서로 밀접하게 연관되어 있다 보니 일부 모형에서는 이 두 가지를 합쳐 하나의 계층으로 묘사하기도 한다.

    • 하나 이상의 링크 계층 프로토콜을 지원하는 물리적 연결 매체도 있으므로, 서로 다른 계층으로 구별해 두는 편이 좋음.
  • 두 호스트 사이에 꼭 한 벌의 물리적 연결 매체와 링크 계층 프로토콜 조합만 쓰는 것은 아니다.

    • 한뭉치의 데이터를 보내는 과정에서 데이터가 서로 다른 여러 매체와 링크 프로토콜을 거쳐 갈 수도 있다.
    • 즉, 네트워크 게임을 하면서 발생하는 데이터를 송신하는 과정에서, 다양한 링크 계층 프로토콜이 두루 이용될 수 있다.
  • 다양한 링크 계층 프로토콜 중에서 가장 많이 접하게 되는 이더넷에 대해서는 알아둘 필요가 있다.


이더넷/802.3

  • 이더넷은 프로토콜 하나가 아니라 이더넷 블루북 표준에 근거한 프로토콜 그룹이다.

  • 이더넷 표준은 1980년도 DEC, 인텔, 제록스가 공동으로 제창

  • 오늘날 이더넷 프로토콜은 IEEE 802.3 표준으로 정의

  • 광섬유, TP 케이블, 동축 케이블 등 매체마다 상응하는 이더넷 파생 프로토콜이 있다.

    • 속도에 따라 파생되는 프로토콜도 있음
  • 여러 호스트를 식별하기 위해 이더넷에서는 매체 접근 제어 주소(Media Access Control address. MAC)를 사용

    • MAC 주소는 이론상 고유한 48비트 숫자
    • 이더넷 네트워크에 연결 가능한 장비 하나하나 마다 고유한 값으로 부여
      • 이러한 장비를 통칭하여 네트워크 인터페이스 컨트롤러(Network Interface Controller. NIC)라고 한다.
    • 범용 고유 식별자(universally unique identifier. UUID)의 일종으로 기기마다 고유한 값을 부여해야 한다.
      • 그래서 NIC 제조업체는 하드웨어 제조 과정에서 MAC 주소를 기기에 새겨 넣음.
    • 첫 24비트는 OUI(organizationally unique identifier)로서 제조업체 식별코드로 IEEE가 제조사마다 고유한 번호를 할당해준다.
    • 나머지 24비트를 고유하게 할당하는 일은 제조업체 책임.
  • 이더넷만 MAC 주소를 사용하는 것은 아니고, 와이파이나 블루투스 등 대부분의 IEEE 802 링크 계층 프로토콜에서 사용

  • 이더넷 패킷 구성

    • 모든 이더넷 패킷은 0x55 7개에 0xD5 1개 총 8바이트의 16진수로 시작.
      • 이를 프리앰블(preamble)과 SFD(start frame delimiter)라 한다.
      • 밑단 하드웨어는 이러한 이진수 패턴을 체크하여 동기화를 맞추고 새 프레임을 받을 준비를 한다.
      • 프리앰블과 SFD는 보통 NIC 하드웨어가 걸러내며, 프레임을 구성하는 나머지 바이트 열을 이더넷 모듈에 넘겨 처리한다.
    • SFD 뒤에 따라붙는 6바이트는 프레임의 수신자로 설정된 기기의 MAC 주소를 나타냄
      • 브로드캐스트 주소를 의미하는 특수 MAC주소도 있음.
        • FF:FF:FF:FF:FF:FF로 나타내고 LAN 상 연결된 모든 호스트에 전달하고자 할 때 사용
    • 길이/종류 필드는 오버로드하여 길이나 종류 둘 중 하나로 사용.
      • 길이 필드로 사용하는 경우 프레임에 포함된 페이로드의 길이를 바이트 단위로 나타낸다.
      • 종류 필드로 사용하는 경우 이더타입(EtherType) 고유 식별자 값을 기록해 페이로드 내 데이터를 어떻게 해석해야 하는지 표시
      • 이더넷 모듈이 이 필드를 처리할 때 정확하게 해석할 수 있게, 이더넷 표준은 페이로드의 최대 길이를 1500바이트로 정의해두었다.
        • 이를 최대 전송 유닛(maximum transmission unit. MTU)라 하며, 한 번 전송에 최대한 담을 수 있는 데이터의 양을 뜻함.
        • 오늘날 이더넷 NIC는 1500바이트를 넘어서는 정보 프레임을 지원하기도 함.
        • 최대 9000바이트 까지 MTU를 갖게 되는데 이를 지원하는 NIC는 프레임 헤더에 특정 이더타입 값을 기록하여 밑단 하드웨어에서 수신된 데이터에 따라 프레임의 크기를 계산한다.
      • 이더넷 표준은 이더타입의 최솟값을 0x0600, 즉 10진수로 1536으로 정해둠.
        • 그러므로 길이/종류 필드 값이 1500이하인 경우에는 길이로 해석하고, 1536 이상인 경우에는 종류로 판단
    • 페이로드(payload)란 프레임에 담겨 전송되는 데이터 그 자체를 뜻한다.
      • 대개 원하는 호스트로 전달하고 싶은 네트워크 계층 패킷이 담겨 있다.
    • 프레임 체크 시퀀스(frame check sequence. FCS)
      • CRC32 (32-bit cyclic redundancy checksum) 값
      • 여러 값에 걸쳐 연산하여 얻은 체크섬 값
      • 연산에 포함되는 것은 발신자와 수신자 주소 각각, 길이/종류 필드, 페이로드, 그리고 패딩 값 등
      • 이더넷 하드웨어가 데이터 수신 시 이 값을 검사하여 전송된 데이터가 손상되었는지 판단
      • 만일 손상된 경우 프레임을 폐기해버림
        • 이더넷이 비록 데이터 전송을 보장해 주지는 못하지만 적어도 훼손된 값이 전달되지 않도록 최소한의 노력은 하는 셈
  • 이더넷 패킷에 대한 요약

    • 네트워크 상 호스트 중 하나가 해당 프레임을 받으면 호스트가 프레임을 읽어보고 그 수신자가 마침 자신일 때, 길이/종류 필드의 값에 따라 페이로드에서 데이터를 꺼내어 처리한다.
  • 초기엔 소규모 이더넷 네트워크에선 허브(hub)라는 장비로 여러 호스트를 한데 묶어 연결했다.

    • 이런식으로 연결된 네트워크에선 이더넷 패킷의 전기 신호가 네트워크상 모든 호스트에 전달되었는데, 그 패킷이 자기 것인지 아닌지 여부는 각 호스트가 스스로 판단해야 했다.
    • 네트워크 규모가 확장 될수록 이 같은 방식은 효율이 저하될 수 밖에 없었다.
  • 오늘날 최신 네트워크에서는 스위치(switch)라는 장비로 여러 호스트에 연결한다.

    • 스위치의 포트에 호스트를 연결해 두면 스위치는 그 호스트의 MAC주소, 혹은 IP 도 같이 기억해 두었다가 그 주소로 패킷을 전달할 일이 있을 때, 연결된 여러 호스트에 일일이 보내지 않고도 해당 호스트를 특정하여 최단경로로 보낼 수 있다.


네트워크 계층

  • 링크 계층만 있어도 주소가 부여된 호스트 사이에 데이터를 주고 받기에 충분할 것 같은데 어째서 TCP/IP 같은 부가적인 계층이 필요할까?
    • MAC 주소가 하드웨어에 각인되어 유연성이 떨어진다.
      • 웹서버를 하나 열었는데 인기를 끌어 매일 수천명의 사용자가 이더넷으로 방문한다고 가정.
      • 링크 계층만 써서 서비스를 하면 서버에 접속하기 위해 이더넷 NIC 장비의 MAC 주소를 사용자들이 알아야한다.
      • 어느날 과부하를 견디지 못하고 NIC 카드가 고장난 경우 새 NIC 카드를 장착해야 하는데 새 카드의 MAC 주소는 이전과 달라지기 때문에 사용자는 더이상 이전 주소로 접속할 수 없게 된다.
      • 따라서 쉽게 설정할 수 있는 주소 체계가 MAC 주소 위에 병행하여 필요하다.
    • 링크 계층으론 인터넷을 보다 작은 네트워크망으로 나눌 수 없다.
      • 전체 인터넷이 링크 계층으로만 되어 있다고 하면 모든 컴퓨터가 단일망에 연결되어 있어야 한다.
      • 이더넷에서는 각 프레임을 네트워크상 모든 호스트에 전달해야하고, 전송자가 애초 의도한 수신자가 바로 자신인지 여부는 호스트 스스로 판단해야 한다.
      • 프레임 하나하나를 보낼 때마다 지구상 연결된 모든 호스트로 일일이 전달해야 한다.
      • 네트워크망을 지역마다 서로 다른 보안 영역으로 구분해 둘 수단이 없다.
      • 같은 사무실 내 호스트에서만 메시지를 브로드캐스트하거나 집 안에 있는 컴퓨터 사이에서만 파일 공유할 수 있는 수단이 없다.
    • 링크 계층에는 한 종류의 링크 프로토콜을 그와 다른 링크 프로토콜로 번역하는 방법이 정의 되어 있지 않다.
      • 여러 종류의 물리 계층과 링크 계층 프로토콜을 두는 까닭은 바로 서로 상이한 네트워크 사이에서 용도에 가장 알맞은 최적의 구현을 각자 선택하게끔 하자는 근본 철학에서 비롯된다.
      • 그러므로 링크 계층 위에 별도의 주소체계를 두어 하나의 링크 프로토콜과 다른 링크 프로토콜이 서로 통신할 방법을 규정할 필요가 있다.
  • 네트워크 계층의 역할은 링크 계층 위에 논리 주소 체계 인프라를 구축하는 것.
    • 주소 걱정 없이 쉽게 호스트 하드웨어를 교체할 수 있다.
    • 여러 호스트를 그룹으로 묶어 서브네트워크로 격리할 수 있다.
    • 멀리 떨어진 서브네트워크 사이에 링크 계층 프로토콜이나 물리적 매체가 각기 다르더라도 서로 통신할 수 있다.


IPv4

  • 오늘날 네트워크 계층에 필요한 기능을 구현하는데 가장 널리 이용되는 프로토콜.
  • 논리 주소 체계로 각 호스트마다 개별적인 주소를 부여
  • 서브넷 체계로 주소 공간의 논리적 부분집합을 나누어 물리적 서브네트워크를 정의하는데 사용
  • 라우팅 체계로 서브넷 사이에서 데이터를 서로 전달

IP 주소와패킷 구조
  • IPv4의 핵심은 바로 IP 주소.

  • 인터넷 상 호스트마다 고유한 IP 주소를 부여해 두면, 발신 호스트가 패킷을 보낼 때 패킷 헤더에 목적 호스트의 IP 주소를 기록하기만 하면 된다.

  • 패킷에는 우선 헤더 자리를 마련해 네트워크 계층 기능에 필요한 데이터를 담아두고 그 뒤에 윗단 계층의 데이터를 전송할 페이로드가 붙는다.

    • 버전(4비트) : 이 패킷이 지원하는 IP 종류를 표시.
      • Ipv4라면 이 숫자는 4가 된다.
    • 헤더길이(4비트) : 헤더의 길이를 32비트 워드로 표시.
      • IP 헤더 뒷부분에 옵션 필드가 여럿 붙을 수 있으므로 헤더의 길이는 가변적
      • 길이 필드에 정확히 어디서 헤더가 끝나고 이어 포장된 실제 데이터가 시작되는지 나타내주어야 한다.
    • 서비스 종류(8비트) : 혼잡 제어나 서비스 식별자 등 다양한 용도로 사용.
    • 패킷 길이(16비트) : 전체 패킷의 길이를 바이트 단위로 표시
      • 길이는 헤더와 페이로드를 더한 것.
      • 16비트로 나타낼 수 있는 최대 숫자 65535(바이트)가 최대 패킷의 길이.
      • IP 헤더의 최소 길이는 20바이트이므로 Ipv4 패킷에서 페이로드가 담을 수 있는 최대 길이는 65515 바이트
    • 분열 식별자(16비트), 분열 플래그(3비트), 분열 오프셋(13비트) : 분열된, 즉 조각난 패킷을 다시 조립하는데 사용
    • TTL(time to live)(8비트) : 패킷을 전달할 수 있는 횟수 제한
    • 프로토콜(8비트) : 페이로드 내용을 해석하는 데 어떤 프로토콜을 써야 하는지 나타낸다.
      • 윗단 계층이 데이터를 어떻게 다루는지 나타낸다는 점에서 이더넷 프레임의 이더필드와 비슷
    • 헤더 체크섬(16비트) : IPv4 헤더의 무결성을 검증하는데 사용하는 체크섬을 기록.
      • 헤더 부분만 계산해 둔 것임에 유의
      • 페이로드의 무결성을 검증하는 것은 윗단 계층의 몫
      • 링크 계층 프로토콜에서 이미 체크섬으로 프레임 전체의 무결성 검사를 하는 경우(예를 들어 이더넷헤더의 FCS 필드)가 많기 때문에 불필요한 편.
    • 발신지 주소(32비트), 목적지 주소(32비트) : 패킷 발신지와 목적지의 IP 주소
      • 목적지의 경우 특수 주소값을 쓰면 여러 호스트로 동시에 패킷을 보낼 수 있다.


직접 라우팅과 주소 결정 프로토콜(ARP)

  • 서로 다른 링크 계층 프로토콜로 연결된 네트워크 사이에 IPv4로 어떻게 패킷을 전달하는지 이해하려면, 먼저 단일 링크 계층 프로토콜의 단일 네트워크에서 패킷이 전달되는 방식부터 이해해야한다.

  • IPv4 프로토콜은 IP 주소로 패킷의 목적지를 지정.

  • 링크 계층이 패킷을 전달하게 하려면 먼저 IP 주소를 링크 계층이 이해할 수 있는 주소 형태로 바꿔 프레임에 포함해주어야 한다.

  • IP주소는 링크 계층이 아닌 네트워크 계층의 개념이기 때문에 IP 주소만으로는 이더넷 모듈을 통해 패킷을 전달할 수 없다.

  • 링크 계층은 IP 주소를 이에 대응하는 MAC 주소로 변환하기 위해 주소 결정 프로토콜(address resolution protocol. ARP)를 사용한다.

    • ARP는 기술적으로는 링크 계층 주소를 직접 사용하는 링크 계층 프로토콜로서 네트워크 계층이 제공하는 라우팅을 필요로하지 않는다.
    • 그렇지만 IP주소를 포함하는 등 네트워크 계층의 추상화를 침범하는 부분이 있으므로 전적으로 링크 계층 프로토콜로만 보기보다는 두 계층 사이의 다리 역할을 한다고 이해하면 좋다.
  • ARP 구성

    1. NIC가 어느 MAC 주소에 대응되는지 질의하는 패킷 구조

    2. 짝을 이루는 여러 NIC와 MAC 주소 쌍을 정리해둔 표

      IP AddressMAC Address
      18.19.0.101:01:01:00:00:10
      18.19.0.301:01:01:00:00:30

ARP 절차
  1. IP를 구현한 모듈이 링크 계층을 거쳐 어떤 호스트에 패킷을 보내고자 할 때, 먼저 수신자의 IP 주소에 대응하는 MAC 주소를 ARP 테이블에서 찾아본다.

  2. 테이블에서 MAC 주소를 찾았다면 IP 모듈은 해당 MAC 주소를 포함한 링크 계층 프레임을 만들어 이를 링크 계층 모듈에 전달하여 발신한다.

  3. 테이블에서 찾지 못한 경우 ARP 모듈이 링크 계층 네트워크에서 도달 가능한 모든 호스트에 아래와 같은 구조의 ARP 패킷을 발신하여 올바른 MAC 주소를 찾고자 시도하게 된다.

    • 하드웨어 종류(16비트) : 링크 계층이 호스트된 하드웨어 종류를 정의
      • 이더넷의 경우 1
    • 프로토콜 종류(16비트) : 네트워크 계층 프로토콜의 이더타입 값과 일치
      • IPv4라면 0x0800
    • 하드웨어 주소 길이(8비트) : 링크 계층 하드웨어 주소의 길이를 바이트로 나타냄
      • 대부분의 경우 MAC 주소는 6바이트
    • 프로토콜 주소 길이(8비트) : 네트워크 계층 논리 주소의 바이트 길이
      • IPv4의 IP 주소 길이는 4바이트
    • 오퍼레이션(16비트) : 1 또는 2의 값. 이 패킷이 정보 요청인지(1) 아니면 응답인지(2)를 지정
    • 발신지 하드웨어 주소(가변길이), 발신지 프로토콜 주소(가변길이) : 각각 패킷 발신지의 하드웨어 주소 및 네트워크 계층 주소를 나타냄
      • 이들 주소의 길이는 패킷 앞부분에 명시된 길이 필드와 일치해야한다.
    • 목적지 하드웨어 주소(가변길이), 목적지 프로토콜 주소(가변길이) : 각각 패킷 목적지의 하드웨어 주소 및 네트워크 계층 주소를 나타냄
      • 주소 질의를 요청하는 경우 목적지 하드웨어 주소는 알수 없는 상태이므로 패킷을 받는 측에선 이 내용을 무시함
  4. 3번의 과정을 세분화

    1. 호스트 A가 B의 MAC 주소를 모르는 경우 ARP 요청 패킷을 만드는데, 오퍼레이션 필드는 1로, 발신지 프로토콜 주소 필드는 18.19.0.1로 발신지 하드웨어 필드는 01:01:01:00:00:10, 목적지 프로토콜 주소 필드는 18.19.0.2로 각각 설정
    2. 이 패킷을 이더넷 프레임에 감싸 이더넷 브로드캐스트 주소 FF:FF:FF:FF:FF:FF로 발신
      • 브로드캐스트 주소를 사용하면 네트워크 상 모든 호스트가 이 프레임을 받아 살펴보게된다.
    3. 호스트 C는 패킷을 받아도 응답하지 않는다.
      • IP 주소가 패킷상 목적지 프로토콜의 주소와 다르기 때문
    4. 호스트 B는 IP가 일치하므로 자신의 ARP 패킷을 하나 만들어 응답
      • 자기 주소를 발신지로, 호스트 A의 주소를 목적지로
    5. 호스트 A가 패킷을 받으면 새로 받은 주소로 ARP 테이블의 호스트 B에 대한 MAC 주소를 갱신
    6. 이를 기다리던 IP 패킷을 이더넷 프레임에 포함하여 호스트 B의 MAC 주소로 전송
    • Note
      • 호스트 A가 ARP 요청을 네트워크상 모든 호스트에 처음 브로드캐스트할 때, 호스트 A 자신의 MAC주소와 IP 주소를 포함해서 보낸다.
      • 이렇게 하면 네트워크에 연결된 다른 호스트들이 호스트 A의 정보로 미리 ARP 테이블을 갱신해둘 수 있다.
      • 아직은 호스트 A의 정보가 필요 없다고 해도, 미리 갱신해두면 나중에 통신할 필요가 생겼을 떄 ARP 요청부터 보내지 않아도 되므로 요긴하다.
      • 악성 호스트가 모든 IP를 자기 것인양 조작한 ARP 패킷을 뿌릴 수 있다.
      • ARP 정보가 검증된 것인지 확인할 방도가 없다면 스위치 장비가 의도치 않게 모든 패킷을 악성 호스트에 전달해 바치는 결과가 나타날 수 있다.
      • 패킷을 훔쳐보는데 그치지 않고 전달되어야 할 패킷이 전달되지 못하여 네트워크 전체의 트래픽이 혼란에 빠지게 될 수 있다.


서브넷과 간접 라우팅

  • 두개의 큰 회사(알파와 브라보)가 있다고 가정 (각각 100대의 호스트를 가지고 있음)

    • 각 회사는 대규모 내부망을 구축
    • 양 사의 네트워크를 서로 연결하여 메시지를 주고 받고자 함
    • 이더넷 케이블을 링크 계층 네트워크에 연결하는 경우
      • 이더넷 패킷은 네트워크상 모든 호스트를 거쳐야 함
      • 기존의 100대의 호스트에 전달되던 이더넷 환경에서 다른 회사의 네트워크에 연결되면 200대의 호스트로 전달됨. (트래픽 두배 증가)
      • 특정 호스트에만 전달되면 될 패킷이 전체 호스트에 전달되므로 보안상으로도 문제가 있음.
    • 링크 계층 수준에서 직접 연결되지 않은 호스트 사이에서도 서로 패킷을 주고받을 수 있게 네트워크 계층에서 라우팅할 필요가 있음.
  • 두 회사의 네트워크 계층 연결

    • 호스트 R은 라우터라 불리는 특수 형태의 호스트
    • 라우터 한대에 NIC가 여러개 장착됨
    • 각 NIC마다 고유 IP 주소가 배정
    • 네트워크 알파의 모든 IP 주소의 공통 접두사는 18.19.100
    • 네트워크 브라보의 모든 IP 주소의 공통 접두사는 18.19.200
    • 서브넷 마스크(subnet mask)는 32비트 숫자로서, IP 주소와 동일하게 숫자 네 개를 마침표로 구분
      • 어느 두 호스트의 IP주소를 각각 서브넷 마스크와 비트 AND 연산하여 그 결과가 같으면 두 호스트는 같은 서브넷에 속함.
      • 브로드캐스트 주소는 네트워크 주소상 서브넷 마스크 영역 외의 비트를 모두 1로 한값.
        • 18.19.100.1의 서브넷이 255.255.255.0이라면 가용 비트는 맨 뒷자리 8비트이므로 8비트가 모두 1이되면 255가 됨.
        • 즉, 18.19.100.255가 브로드캐스트 주소가 된다.
    • CIDR(classless inter-domain routing) 표기법
      • 서브넷 마스크를 이진수로 쓰면 1이 n개 나온 뒤 0이 (32-n)개 붙는 형식
        • 255.255.255.0이면 1이 24개, 0이 8개.
        • 32-24(1개수) = 8(0개수)
      • 서브넷을 표기할 때 먼저 네트워크 주소를 쓰고 슬래시(/)로 구분한 뒤 서브넷 마스크의 1인 비트 개수를 적는 식
      • 위 예제의 IP주소를 CIDR로 표기하면 1의 개수가 24개이므로 18.19.100.0/24
  • 각 호스트의 IP 모듈은 라우팅 테이블을 보유하여 서브넷 간 패킷 전달에 이용

    • 원격 호스트에 IP 패킷을 보내도록 어떤 호스트의 IPv4 모듈에 요청하면 먼저 IP 모듈은 ARP 테이블을 써서 직접 라우팅할지, 아니면 간접 라우팅할지부터 결정해야 한다.

    • 이를 위해 라우팅 테이블을 참조

    • 라우팅 테이블엔 도달 가능한 목적지 서브넷마다 패킷을 어떻게 전달할지에 대한 정보가 한 줄씩 기록되어있다.

      • 호스트 A1의 라우팅 테이블

        행 번호목적지 서브넷게이트웨이NIC
        118.19.100.0/24NIC 0(18.19.100.2)
        218.19.200.0/2418.19.100.1NIC 0(18.19.100.2)
      • 호스트 B1의 라우팅 테이블

        행 번호목적지 서브넷게이트웨이NIC
        118.19.200.0/24NIC 0(18.19.200.2)
        218.19.100.0/2418.19.100.1NIC 0(18.19.200.2)
      • 호스트 R의 라우팅 테이블

        행 번호목적지 서브넷게이트웨이NIC
        118.19.100.0/24NIC 0(18.19.100.1)
        218.19.200.0/2418.19.100.1NIC 1(18.19.200.1)
    • 목적지 서브넷 열은 대상 IP 주소가 포함된 서브넷을 가리킴

    • 게이트웨이 열은 다른 서브넷의 링크 계층으로 패킷을 전달하기 위해 거쳐야할 현재 서브넷상 다음 호스트의 IP 주소를 가리킴

    • 게이트웨이 호스트는 직접 라우팅으로 도달 가능해야 한다.

      • 게이트웨이 란이 비어있으면 목적지 서브넷 전체가 직접 라우팅으로 도달 가능하다는 뜻으로 링크 계층으로 직접 래킷을 보낼 수 있다.
    • NIC 열은 패킷을 전달하는 데 사용할 NIC가 어느 것인지 가리킴

  • 18.19.100.2에 위치한 호스트 A1이 패킷 18.19.200.2의 호스트 B1에 전달할 때 다음 과정을 거친다.

    1. 호스트 A1이 발신자 주소 18.19.100.2, 수신자 주소 18.19.200.2로 IP 패킷을 만든다.
    2. 호스트 A1의 IP 모듈은 라우팅 테이블을 한 줄씩 위에서 아래로 훑어가다 IP 주소 18.19.200.2를 포함하는 목적지 서브넷 항목 중 첫번째 것을 찾는다.
      • 위 표에서 두번째 행이 찾아짐
    3. 제 2행에 등록된 게이트웨이 주소는 18.19.100.1이다.
      • 호스트 A1은 ARP와 이더넷 모듈을 이용해 패킷을 이더넷 프레임으로 꾸려 18.19.100.1에 해당하는 MAC 주소를 가진 호스트로 발신한다.
      • 이 패킷은 곧 호스트 R에 도착
    4. 호스트 R의 NIC 0번, 곧 IP 주소가 18.19.100.1인 이더넷 모듈은 프레임을 받아 그 페이로드가 IP 패킷임을 감지하고 IP 모듈에 올려보낸다.
    5. 호스트 R의 IP모듈은 패킷 주소가 18.19.200.2인 것을 확인하고 해당 IP로 패킷 전달을 시도한다.
    6. 호스트 R의 IP 모듈은 18.19.200.2를 포함하는 서브넷 항목을 라우팅 테이블에서 찾는다.
      • 위 표에서 2행에 해당.
    7. 2행엔 게이트웨이가 없으므로 이 서브넷은 직접 도달 가능
      • NIC 칼럼이 IP주소 18.19.200.1인 NIC 1을 가리킴
      • 이 NIC는 예시로 들었던 네트워크 브라보에 연결되어 있음.
    8. 호스트 R의 IP 모듈은 NIC 1에서 구동 중인 이더넷 모듈에 패킷을 넘겨준다.
      • IP 모듈은 ARP와 이더넷 모듈을 이용해 패킷을 이더넷 프레임으로 꾸려 IP 주소 18.19.200.2에 해당하는 MAC 주소를 가진 호스트로 발신
    9. 호스트 B1의 이더넷 모듈이 프레임을 받아 그 페이로드가 IP 패킷임을 감지하고 IP 모듈에 올려보낸다.
    10. 호스트 B1의 IP 모듈은 수신자 IP 주소가 자기 것임을 확인
    • 상위 계층에서 계속 처리할 수 있게 페이로드의 내용을 윗단 계층으로 올려보낸다.
  • 내부 네트워크에서 인터넷으로 패킷을 보내려면 어떻게 해야 할까?

    • 인터넷 서비스 공급자(internet service provider, ISP)로부터 공인 IP와 게이트웨이를 제공받아야 한다.

    • ISP로부터 18.181.0.29, 게이트웨이 18.181.0.1을 제공 받았다고 가정

      • 인터넷 접근이 가능한 호스트 A1의 라우팅 테이블

        행 번호목적지 서브넷게이트웨이NIC
        118.19.100.0/24NIC 0(18.19.100.2)
        218.19.200.0/2418.19.100.1NIC 0(18.19.100.2)
        30.0.0.0/018.19.100.1NIC 0(18.19.100.2)
      • 인터넷 접근이 가능한 호스트 B1의 라우팅 테이블

        행 번호목적지 서브넷게이트웨이NIC
        118.19.200.0/24NIC 0(18.19.200.2)
        218.19.100.0/2418.19.200.1NIC 0(18.19.200.2)
        30.0.0.0/018.19.200.1NIC 0(18.19.200.2)
      • 인터넷 접근이 가능한 호스트 R의 라우팅 테이블

        행 번호목적지 서브넷게이트웨이NIC
        118.19.100.0/24NIC 0(18.19.100.1)
        218.19.200.0/2418.19.100.1NIC 1(18.19.200.1)
        318.181.0.0./2418.181.0.1NIC 2(18.181.0.29)
        40.0.0.0/018.181.0.1NIC 2(18.181.0.29)
    • 목적지 서브넷 주소 0.0.0.0/0은 기본 주소(default address)라 하는데, 모든 IP가 이 서브넷에 포함되기 때문

      • 호스트 R이 패킷을 받았는데 그 대상 주소가 1~3열 어느것에도 해당하지 않는 경우라면 마지막의 기본 주소에는 항상 대응이 된다.
      • 해당 패킷은 새로 장착한 NIC를 거쳐 ISP의 게이트웨이로 전달되며, 거기서 다른 여러 게이트웨이를 잇는 경로를 거쳐 패킷이 원래 의도한 목적지에 언젠가 도착할 수 있을 것이다.
      • 호스트 A1과 B1에도 인터넷 패킷을 호스트 R로 전달하게끔 기본 주소를 새 항목으로 추가해두었기 떄문에 인터넷용 패킷을 호스트 R을 거쳐 ISP로 라우팅할 수 있다.
  • 게이트웨이가 패킷을 받아 전달할 때마다 IPv4 헤더의 TTL 필드 값이 하나씩 차감된다.

    • TTL 값이 0이되면 패킷이 어디에 체류 중이었건 상관 없이 마지막으로 차감했던 호스트의 IP 모듈이 패킷을 폐기한다.
    • 반복 순환되도록 라우팅된 경로가 있으면 해당 패킷이 영원히 인터넷을 떠돌아다니게 되기 때문에 이를 방지하기 위해서 TTL이 필요하다.
    • TTL 값을 변경하면 헤더 체크섬도 다시 계산해야하는데, 이 때문에 호스트가 패킷을 처리하고 전달하는데 약간의 지체가 발생한다.
  • TTL이 0이 되는 것 외에도 패킷이 누락되는 경우가 있다.

    • 많은 양의 패킷이 라우터의 NIC에 소화할 수 없을 정도로 쏟아져 들어오면 NIC가 패킷을 그냥 무시해버릴 수도 있다.
    • NIC가 여러 개 장착된 라우터에 패킷이 들어오는데 NIC 중 하나가 이들 패킷 전부를 외부로 전달하여야 하는 경우, 그 NIC가 처리를 감당할 수 있을 정도로 빠르지 않다면 패킷 중 일부가 누락될 수 있다.
  • 여러가지 누락될 수 있는 경우로 인해 IPv4를 포함하여 네트워크 계층의 모든 프로토콜은 비신뢰성 프로토콜로 취급한다.

    • 패킷이 도착한다 해도 원래 보낸 순서대로 도착한다는 보장도 없고, 단 한번만 전달된다는 보장도 없다.
    • 네트워크가 혼잡하다보면 라우터가 패킷 하나는 이쪽 경로로 라우팅하고 같은 목적지의 다른 패킷은 다른 쪽 경로로 라우팅할 수 있다.
      • 경로는 저마다 길이가 다를 것이고 그러다 보니 나중에 보낸 패킷이 먼저 도착할 수도 있다.
    • 어떤 경우엔 패킷이 여러 경로로 동시에 전달될 수도 있는데, 그 중 하나가 먼저 도착하고 나머지가 또 다시 도착하는 경우도 생긴다.

중요 IP 주소
  • 127.0.0.1
    • 루프백(loopback) 또는 로컬 호스트 주소(localhost address)
    • 패킷을 127.0.0.1로 보내려하면 IP 모듈은 외부로 패킷을 보내지 않는다.
    • 대신 이 패킷을 고스란히 다시 받은 것처럼 만들어 윗단 계층이 처리하게 올려보낸다.
  • 255.255.255.255
    • 제로 네트워크 브로드캐스트 주소(zero network broadcast address)
    • 패킷을 현재 로컬 링크 계층 네트워크의 모든 호스트로 브로드캐스트하지만, 라우터를 거쳐 외부로 나가지는 못하게 한다.


패킷 분열

  • MTU 혹은 최대 페이로드 크기는 이더넷 프레임에서 1500바이트

  • IPv4 패킷의 최대 크기는 65535 바이트

  • IP 패킷을 하단 링크 계층 프레임으로 감싸서 보내야 한다면 어떻게 링크 계층의 MTU 보다도 큰 패킷을 처리할 수 있을까?

    • 답은 바로 패킷을 분열하는 것(fragmentation)
    • IP 모듈이 목표 링크 계층의 MTU보다 큰 패킷을 송신해야 할 때, IP 모듈은 패킷을 MTU 크기의 여러 조각으로 패킷을 분열한다.
    • 분열된 IP 패킷은 보통의 IP 패킷과 외견상 차이가 없지만 헤더의 몇몇 필드에 특정 값이 지정된다.
      • 분열 식별자 필드 (16비트) : 분열된 조각이 원래 어느 패킷에 있었는지 나타내는 숫자
        • 한 패킷에서 쪼개져 나온 모든 조각은 이 필드의 값이 같다.
      • 분열 플래그 필드 (13비트) : 오프셋을 8바이트 블록 단위로 나타내며, 원래 패킷의 시작 지점부터 따졌을 때 이 조각의 위치를 가리킨다.
        • 각 조각의 숫자는 서로 모두 달라야 한다.
        • 13비트로 65535바이트까지 오프셋을 가리킬 수 있어야 하므로 8바이트 블록 단위로 표기
        • 항상 8로 곱해서 사용해야 하며, 8의 배수가 아닌 값은 오프셋으로 지정할 수 없다.
        • 0x02로 지정하면 DF(don't fragment), 즉 분열 금지 플래그가 된다.
          • 패킷 크기보다 MTU 크기가 작은 링크로 패킷을 전달하려 하면 IP 모듈은 DF 플래그가 설정된 패킷의 경우 분열하는 대신 그냥 걸러버린다.
      • 분열 오프셋 필드 (3비트) : MF 플래그(more fragments flag)
        • 아직 남은 조각이 더 있다는 의미
        • 이 플래그가 켜진 패킷을 받은 호스트는 남아있는 다른 조각을 모두 받을 때까지 처리를 미뤄두었다가 다 받은 후에서야 패킷을 다시 조립해 윗단 계층으로 넘겨야 한다.
        • 마지막 조각의 플래그는 항상 꺼져 있어야 한다. 그래야 원래 패킷에 더이상 남은 조각이 없다는 걸 수신측에 알려줄 수 있다.
    • IP 모듈이 IP 패킷을 여러 조각으로 쪼갤 때, 쪼갠 조각마다 패킷을 만들고 필드 값을 적절히 채워 넣는다.
  • IPv4 패킷의 분열 예제

    • 분열 식별자 필드 값은 모두 12로 세 조각이 모두 같은 패킷에서 비롯되었음을 나타냄
    • 첫 번째 조각에 MF 플래그가 설정되어 있고 분열 오프셋은 0으로 원래 패킷 첫 부분의 데이터임을 나타냄
      • 이 때 패킷의 필드 값이 1500
      • 대개 IP 모듈은 조각 수를 줄이기 위해 조각을 나눌 때 가능한 한 크게 나눈다.
    • IP 헤더가 20바이트 이므로 조각 데이터에 총 1480바이트를 담을 수 있다.
      • 다음 조각 데이터의 오프셋이 1480에서 시작해야 함
      • 분열 오프셋 필드는 8바이트 블록 단위로 기재해야 하므로 1480 나누기 8 값이 기재된다. 즉, 185
    • 마지막 세번째 조각은 MF 플래그가 꺼져 있어 이것이 마지막 조각임을 나타냄
    • 원래 패킷에서 헤더를 제외한 데이터 길이는 3000바이트
      • 이를 쪼개면 첫번째 조각이 1480바이트
      • 두번째도 1480바이트
      • 세번째 조각에는 남은 데이터가 40바이트
      • 40바이트에 헤더 20바이트를 붙이면 60바이트가 된다.
  • 수신자가 패킷을 올바르게 처리하려면 패킷 조각 하나하나가 최종 호스트까지 전달되어 원래의 쪼개기 전 패킷으로 재조립되어야 한다.

    • 패킷 조각을 받으면 수신자 IP 모듈은 64KB(IP 패킷의 최대 크기) 버퍼를 만들고 조각의 데이터를 버퍼상 정확한 오프셋 위치에 복사해 넣는다.
    • 버퍼에는 발신자 IP 주소와 분열 식별자 번호를 붙여두어 이 후 추가로 패킷 조각을 받게 되면 조각의 발신자와 식별자를 토대로 해당하는 버퍼를 끄집어내어 새로 받은 데이터를 복사해 나간다.
    • MF 플래그가 꺼져 있는 조각을 받으면 원래 패킷의 길이를 계산할 수 있는데, 조각의 길이에 조각의 오프셋을 더하면 된다.
    • 패킷 하나를 온전히 조립해내도록 모든 데이터 조각을 받으면 IP 모듈은 조립된 패킷을 윗단 계층에 넘겨 계속 처리한다.
  • IP 패킷 분열의 비효율적인 면

    1. 네트워크로 실제 보내는 데이터양이 증가한다.
      • 헤더 정보 20바이트가 조각마다 더해지므로 적은 양이지만 누적되면 부담이 될 수 있다.
    2. 조각 중 하나라도 잃어버리면 다른 조각 전체를 몽땅 버려야 한다.
      • 대개의 경우 분열 기능 자체를 쓰지 않는 것이 좋다.
      • 대신에 IP 패킷의 크기를 링크 계층 MTU보다 작게 잡는 편이 낫다.
      • MTU 최대 크기은 1500바이트를 조각에서 전부 IP 페이로드에 쓸 수는 없다.
        • 20바이트는 IP 헤더
        • VPN이나 IPSec 등 여타 프로토콜이 필요로하는 데이터와 나눠써야 한다.
        • IP 페이로드는 1300바이트 내외로 잡아야 안전하다.


IPv6

  • IPv4는 32비트 주소 체계로 약 42억개의 고유 IP 주소를 배당할 수 있다.

    • 사설망과 네트워크 주소 변환 덕에 이보다 조금 더 많은 수의 호스트를 인터넷에 연결할 수 있음
  • 이미 32비트 고유 IP 주소는 고갈된지 오래됨

  • 주소 고갈 문제 및 비효율성 해소를 위해 IPv6가 고안되었다.

  • IPv6는 IP 주소의 길이가 128비트

    • 여덟 묶음의 네 글자 16진수로 표현

    • 묶음마다 콜론으로 구분

      형식주소
      줄여 쓰지 않음2001:4a60:0000:08f1:0000:0000:0000:1013
      각 묶음(hexlet)의 앞자리 0을 생략2001:4a60:0:08f1:0:0:0:1013
      연달아 나오는 0 묶음을 생략2001:4a60:0:8f1::1013
      • 각 16진수 묶음의 앞자리 0은 생략 가능
      • 0만 있는 묶음은 통째로 생략해 콜론 두 개로 사용 가능
      • 주소가 항상 16바이트이므로 빠진 숫자에 0을 채워넣으면 원래 모양으로 돌려놓을 수 있다.
    • 첫 64비트는 보통 네트워크를 나타내며 네트워크 접두사(network prefix)라 한다.

    • 나머지 64비트는 개별 호스트를 나타내어 인터페이스 식별자(interface identifier)라 한다.

    • 고정 IP를 사용하려는 경우 인터페이스 식별자를 수동으로 지정해주면 된다.

    • 동적 IP를 사용하려는 경우 식별자를 그때그때 랜덤 생성.

      • 가장 보편적으로 NIC의 EUI-64와 같은 값으로 둔다.
      • EUI-64가 이미 고유한 값으로 보장되기 떄문
      • EUI(Extended Unique Identifier) : IEEE 표준으로써 링크 계층 상에서 유일 식별성을 갖추기 위한 주소 형식
    • 기존 ARP에서 하던 역할은 IPv6의 NDP(neighbor discovery protocol, 인접 노드 발견 프로토콜)가 대체

      • DHCP의 기능도 일부 포함
    • NDP를 이용해 라우터는 네트워크 접두사와 라우팅 정보를 선전하고, 호스트는 각자의 IP 주소와 링크 계층 주소를 질의하고 공시한다.

    • 라우터 레벨에서는 더이상 패킷 분열을 지원하지 않는다.

      • 이로써 모든 분열 관련 필드를 IP 헤더에서 제거하여 패킷의 대역폭을 절약할 수 있다.
      • 링크 계층 라우터가 받은 IPv6 패킷이 처리하기에 너무 크다면 그 라우터는 패킷을 버리고 발신자에게 패킷이 너무 커서 걸러버렸다고 답한다.
        • 응답을 받은 발신자는 더 작은 패킷을 보내는 것으로 대응.
        • 가장 작은 MTU를 예상을 해서 미리 제약을 두는 것보다는 충분히 큰 것을 보내 본 다음에 너무 크다는 응답이 있을 때만 작게 보내면 되므로 한층 유연하고 효율적.


전송 계층

  • 네트워크 계층의 역할은 원격 네트워크상 서로 멀리 떨어진 호스트 사이에 통신을 촉진하는 것.

  • 전송 계층의 역할은 이들 호스트상 개별 프로세스 사이의 통신을 가능케 하는 것.

    • 호스트 한대에 여러 프로세스가 동시에 구동 가능하므로 호스트 A에서 호스트 B로 IP 패킷을 보냈다라는 것으로는 불충분
  • 전송 계층에서는 개별 프로세스로 패킷을 전달하기 위해 포트라는 개념을 도입

  • 포트는 16비트 부호 없는 숫자로서 특정 호스트의 통신 종단점을 나타냄

    • IP주소가 거리의 건물 주소라면 포트는 건물 내 입주한 사무실 번호에 비유할 수 있음
  • 어떤 프로세스가 특정 포트를 바인딩해 두면 전송 계층 모듈은 이후 그 포트로 전달되는 모든 패킷을 그 프로세스에 전달해 준다.

  • 이론상으로는 16비트 내 어떤 포트에든 바인딩하여 자신이 의도하는 어느 용도로든 사용할 수 있다.

    • 같은 호스트의 두 프로세스가 서로 같은 포트에 바인딩 하려 하면 문제가 야기됨
    • 대부분의 운영체제에서 여러 프로세스가 같은 포트에 바인딩하려 할 때 특별한 플래그를 설정해야만 이를 허용
    • 포트를 둘러싼 혼선을 미연에 방지하고자 IANA기구 산하 ICANN 부서에선 포트 번호 등록제를 운영하여 여러 프로토콜과 애플리케이션 개발자가 각자 필요로하는 포트를 등록하여 사용하는 것을 권장한다.
    • 전송 계층 프로토콜 하나당 오로지 하나의 포트만 등록할 수 있다.
    • 포트번호 0~1023까지는 시스템 포트(system port) 또는 예약 포트(reserved port)
      • 사용자 포트와 유사하지만 더 까다롭고 많은 검토 단계를 거쳐야 IANA에 등록할 수 있다.
      • 운영체제에서는 이 포트들을 특별히 취급하여 오직 루트 레벨 프로세스만 시스템 포트에 바인딩할 수 있다.
    • 포트번호 1024~49151까지는 사용자 포트(user port) 또는 등록 포트(registered port)
      • 개발자는 공식적으로 IANA에 이 범위 내 포트 번호를 요청할 수 있다.
      • IANA에서 검토 후 포트 등록을 승인
      • IANA에 다른 프로토콜이나 응용프로그램용으로 이미 등록된 상태라면 사용하지 않는 것이 바람직함.
      • 그렇다고 해서 전송 계층의 구현 수준에서 이를 차단하지는 않음.
      • 예를 들어 mysql이 3306이라는 포트를 사용한다고 해서 응용프로그램 개발자가 3306을 사용하지 못하는 것은 아니지만 IANA에 이미 등록된 포트이므로 가급적 피하는 것이 좋음.
    • 나머지 포트 번호 49152~65535까지는 동적 포트(dynamic port)
      • IANA 관할 밖이며 어느 프로세스가 쓰던 제약이 없다.
      • 동적 포트만 써서 개발하다 나중에 필요한 시점에 IANA에 등록 포트를 요청하는 것이 정석.
  • 응용 프로그램이 사용할 포트를 정하면 이후 전송 계층 프로토콜을 통해 실제 데이터를 보낸다.

    이름약자프로토콜 번호
    전송 제어 프로토콜(transmission control protocol)TCP6
    사용자 데이터그램 프로토콜(user datagram protocol)UDP17
    데이터그램 혼잡 제어 프로토콜(datagram congestion control protocol)DCCP33
    스트림 제어 전송 프로토콜(stream control transmission protocol)SCTP132

UDP (user datagram protocol)

  • 경량 프로토콜로서 데이터를 포장하여 호스트의 어떤 포트에서 다른 호스트의 또 어떤 포트로 전달하는데 사용

  • UDP 데이터그램은 페이로드 앞에 8바이트 헤더를 붙여서 만든다.

    • 발신자 포트(16비트) : 데이터그램의 출처가 되는 포트 번호를 기재
      • 수신자가 발신자에게 응답하고자 할 때 사용
    • 목적지 포트(16비트) : 데이터그램의 목적지가 되는 포트 번호를 기재
      • UDP 모듈은 이 포트에 바인딩해 둔 프로세스에 데이터그램을 전달
    • 길이(16비트) : UDP 헤더와 페이로드의 합친 길이
    • 체크섬(16비트) : 헤더와 페이로드, 그리고 IP 헤더 몇몇 필드를 엮어 계산한 체크섬 값
      • 필수사항은 아님
      • 계산하지 않을 경우 0으로 채운다.
      • 밑단 계층에서 자체적으로 체크섬을 돌려보므로 이 필드는 잘 쓰지 않는 편
  • 각 데이터그램은 자체로 완결된 것으로 두 호스트 간 어떤 공유 상태에도 의존하지 않는다.

    • 일단 패킷을 전송하면 신경쓰지 않아도 된다.
    • 네트워크가 불안정하더라도 트래픽을 제한해 주지않음
    • 데이터를 순서대로 전달해주지 않음
    • 데이터의 전달을 보장해주지 않음


TCP (transmission control protocol)

  • UDP로 호스트 사이에 불연속적인 데이터그램만 주고받을 수 있다면, TCP로는 양쪽의 호스트 사이에 연결을 계속 유지한 채로 신뢰성 있게 데이터의 스트림을 주고 받을 수 있다.

  • TCP는 의도된 수신자에게 모든 데이터를 순서대로 전달하려 최선을 다한다.

    • 이를 위해 UDP에 비해 큰 헤더가 필요
    • 연결된 호스트마다 간단치 않은 연결 상태 추적 메커니즘이 동작함
    • 수신자는 데이터를 받았는지 여부를 발신자에게 ACK(acknowledgment) 할수 있다.
    • 발신자는 ACK가 없는 부분의 데이터를 다시 보낼 수 있다.
  • TCP의 데이터 전송 단위를 일컬어 TCP 세그먼트라 한다.

    • "마디"라는 의미에서 유추할 수 있듯이 TCP는 긴 스트림 데이터를 보내는 용도로 설계됨

    • 이 스트림으로 이어진 여러 마디 중 하나를 잘라 하위 계층의 패킷으로 포장한 것이 세그먼트

    • TCP 헤더가 먼저 오고 그 다음에 세그먼트 데이터가 이어진다.

  • 아래 그림은 TCP 헤더를 나타냄

    • 발신지 포트(16비트), 목적지 포트(16비트) : 전송 계층 포트 번호
    • 시퀀스 번호(32비트) : 단조 증가하는 식별 번호
      • 개념상 TCP로 보내는 각 세그먼트마다 시퀀스 번호가 식별자로 부여됨
      • 발신자와 수신자는 데이터 전송 중도에 답신을 위한 표식으로 이 번호를 사용
    • ACK 번호(32비트) : 발신자가 응답받기를 기다리는 다음 시퀀스 번호
      • TCP는 데이터를 모두 순서를 지켜 전송하므로 호스트가 매번 기다리는 시퀀스 번호는 그 전에 받은 번호에 항상 1을 더한 값이 된다.
      • 수신자가 ACK 번호를 보내면 그 ACK 번호에 해당하는 시퀀스 뿐만 아니라 그 아래 모든 시퀀스를 받았다는 뜻이므로 주의
    • 데이터 오프셋(4비트) : 헤더의 길이를 32비트 워드로 지정
      • TCP헤더와 데이터 사이에 옵션 헤더를 최대 44바이트까지 사용할 수 있다.
      • 데이터 오프셋은 옵션 헤더가 끝나고 데이터가 시작되는 지점을 가리킴
    • 제어 비트(9비트) : 헤더의 메타 정보 플래그를 포함
    • 수신 윈도(16비트) : 발신자가 데이터 전송에 사용하는 버퍼 용량이 얼마나 남았는지 알려주는 역할
      • 흐름제어에 사용
    • 긴급 포인터(16비트) : 세그먼트 데이터 시작 위치를 기준으로 긴급 데이터의 위치를 나타냄
      • 제어 비트에 URG 플래그가 설정된 경우에만 유용

신뢰성

  • 고유하게 식별할 수 있는 패킷을 발신 호스트가 수신 호스트에 보내놓고 확인응답(ACK)을 기다리며, 수신 호스트는 ACK를 기재한 패킷으로 응답

  • 한참동안 ACK가 오지 않으면 송신 호스트는 원래 패킷을 다시 보내본다.

  • 모든 데이터를 보내고 ACK를 받을 때까지 이 절차를 반복

  • TCP가 신뢰성 전달을 하기 위해 채택한 구현 전략에서는 시퀀스 번호 추적과 데이터 재전송이 필요하므로 각 호스트는 열려 있는 모든 TCP 연결에 대해 상태 변수를 유지해야한다.

  • RFC793에 정의된 주요 상태 변수와 표준 약칭

    변수약자정의
    송신 다음 번호SND.NXT호스트가 보낼 다음 세그먼트의 시퀀스 번호
    송신 미확인 번호SND.UNA아직 ACK를 받지 않은 데이터의 가장 앞 시퀀스 번호
    송신 윈도SND.WND호스트가 보낼 수 있는 데이터의 현재 용량(미확인 데이터에 대해 ACK를 받으면 최대 용량으로 리셋)
    수신 다음 번호RCV.NXT호스트가 받을 것으로 예측되는 시퀀스 번호
    수신 윈도RCV.WND호스트가 받을 수 있는 데이터의 현재 용량(수신 버퍼를 초과하지 않도록)

3-웨이 핸드셰이킹

  • 호스트 A가 첫 번쨰 세그먼트를 보내 연결을 시작

    • 이 세그먼트에는 SYN 플래그가 설정되어 있고 초기 시퀀스 번호를 1000으로 지정
    • 이는 호스트 A가 앞으로 시퀀스 번호 1000부터 시작하는 TCP 연결을 시작했다는 것을 호스트 B에게 인지시켜줌
    • 호스트 B는 이에 따라 연결 상태 유지에 필요한 자원을 할당해야 한다.
  • 호스트 B가 연결을 받아줄 수 있는 상황이면 SYN 플래그와 ACK 플래그 둘 다 켜진 패킷으로 응답

    • 이 때 응답 패킷의 ACK 번호는 호스트 A가 처음 보내준 시퀀스 번호 더하기 1
    • 1000번 세그먼트는 잘 받았으니 이제 그 뒤의 세그먼트를 기다리겠다는 의미
  • 호스트 B가 A로 보내는 스트림의 첫 번째 시퀀스 번호(위 예에서는 3000)는 호스트 B가 임의로 선택

  • 호스트 A와 B 사이의 연결에 두 개의 스트림이 한 쌍으로 존재하게 됨

    • 하나는 A에서 B로, 또 하나는 B에서 A로 가는 스트림
    • 각 스트림의 시퀀스 번호 체계가 서로 다르다는 점을 유념
    • A에서 B로 가는 스트림은 호스트 A가 랜덤으로 지정, B에서 A로 가는 스트림은 호스트 B가 랜덤으로 지정.
  • 세그먼트에 SYN 플래그가 켜져 있다는 것은 이제 스트림으로 데이터를 보내기 시작할테니 이 시퀀스 번호 더하기 1을 기준으로 바이트 순서를 매기도록 하라는 의미.

  • 두번째 세그먼트를 보면 SYN외에도 ACK 플래그와 ACK 번호가 포함되어 있는데 이는 아까 보내준 데이터 중 이 ACK 번호까지는 다 받았으니 다음 세그먼트를 보내주는 것으로 알고 있겠다는 의미

  • 호스트 A가 B에게 이 세그먼트를 응답으로 받고 나면 지금 당장은 더 보낼 데이터가 없으므로 호스트 B가 보내준 첫 번째 시퀀스 번호를 잘 받았다고 응답만 해주면 된다.

    • SYN 플래그는 끄고 ACK만 켜서 호스트 B가 보내준 시퀀스 번호에 1을 더한 3001을 ACK 번호로 하여 응답
  • 시간이 초과되어 호스트 A가 SYN-ACK 세그먼트를 받지 못한 경우

    1. 호스트 B가 SYN 세그먼트를 못 받음
    2. B가 응답은 보냈지만 A가 못받음
    • 두 경우 모두 호스트 A는 처음 세그먼트를 다시 보냄
    • 2번의 경우처럼 B가 응답을 했는데 A가 못받은 경우라면 B는 SYN 세그먼트를 두번 받게 되는데, 이 때 B는 A가 SYN-ACK를 받지 못해서 다시 보낸 것으로 유추할 수 있으므로 SYN-ACK 세그먼트를 다시 보낸다.

데이터 전송
  • 데이터를 전송하려면 호스트가 각 세그먼트를 보낼 때마다 페이로드를 실어야한다.
  • 각 세그먼트에는 데이터의 첫 바이트를 가리키는 시퀀스 번호가 붙어 있다.
    • 바이트마다 연속적인 시퀀스 번호가 붙어 있음.
    • 세그먼트의 시퀀스 번호는 이전 세그먼트 번호 더하기 데이터 길이와 같다.
  • 수신자는 세그먼트를 받을 때마다 ACK 패킷에 그 ACK 필드 값을 다음번 받아야 할 시퀀스 번호로 기재하여 응답.
    • 가장 마지막으로 받은 세그먼트 번호 더하기 데이터길이와 같음

  • 그림 2-15에서 호스트 A가 보낸 세그먼트 1301이 유실됨

    • 호스트 A는 1301 이상의 번호를 가진 ACK 패킷이 오길 기다리고 있을 것이다.
  • 시간이 초과되도록 ACK를 못받으면 이상을 감지하고 패킷을 다시 보내야 함

    • 1301 패킷이 호스트 B에 전달되지 않고 유실되었거나.
    • 호스트 B가 받긴 했는데 확인응답이 오던 도중 사라졌거나.
  • 다시 보내려면 원래 데이터의 사본을 가지고 있어야 한다.

    • TCP 동작에서 매우 중요한 부분
    • TCP 모듈은 데이터를 모두 보낸 것에 대한 확인 응답을 받을 때까지 그 데이터를 한 바이트도 빠트리지 않고 들고 있다.
      • 세그먼트를 잘 받았다는 ACK를 받은 후에야 이 데이터를 메모리에서 제거할 수 있다.
  • TCP는 데이터가 순서대로 도착하는 것도 보장

  • 기다리던 시퀀스 번호와는 다른 패킷을 호스트가 받은 경우 처리하는 방법

    1. 순서가 안 맞는 패킷은 그냥 소각해버리고 원래 순서의 패킷이 도착하길 기다림
    2. 일단 버퍼에 저장해 놓지만 ACK도 주지 않고, 응용 계층에 넘기지도 않고 그대로 갖고 있는 것.
      • 시퀀스 번호를 토대로 로컬 스트림 버퍼상 저장할 위치를 계산할 수 있다.
      • 비어 있던 앞쪽 세그먼트들을 모두 빠짐없이 받았다면 그때야 비로소 맨 마지막 세그먼트로 ACK를 날리고 통째로 응용 계층에 넘겨 계속 처리한다.
      • ACK는 그 앞의 데이터를 모두 받았다는 뜻이므로 발신자는 마지막 ACK만 받았다고 해서 앞의 내용을 다시 보낼 필요가 없다.
      • ACK를 기다리는 쪽에서도 이전 세그먼트에 대한 ACK를 받지 못했더라도 마지막에 받은 ACK의 시퀀스 번호가 최신이라면 이전 세그먼트들은 처리 된 것으로 간주한다.
  • MTU가 1500 바이트이므로 IPv4 헤더가 최소 20바이트를 차지하고, TCP 헤더가 적어도 20바이트를 가져가면 분열이 없다는 전제하에 이더넷을 거쳐 TCP 세그먼트 하나에 실어보낼 수 있는 데이터는 1460바이트가 된다.

    • 이를 MSS(maximum segment size)라 한다.
  • TCP 연결 도중 한 세그먼트를 보낸 뒤 ACK를 받아야만 다음 세그먼트를 보내야하는 제약이 있다면 대역폭이 심각하게 제한되고 말 것이다.

    • 북미 대륙 횡단에 필요한 RTT는 대략 30 밀리초 내외
      • RTT(round trip time) = 발신자가 세그먼트를 보내 수신자가 받는데 걸리는 시간 + 수신자가 ACK를 보내 발신자가 받는 시간
    • 대역폭은 1500바이트/0.03초 = 50kbps
      • 대역폭 = MSS / RTT
    • 위 전제라면 아무리 고속의 회선을 깔아도 중간에 이더넷 링크가 하나 끼어 다니면 모뎀 속도밖에 나오지 않는다.
  • TCP는 연결 중에 ACK 없이도 여러 세그먼트를 한꺼번에 보낼 수 있다.

    • 여러 세그먼트를 한꺼번에 보내는 것이 무제한으로 가능하다면 그것도 문제가 된다.
    • 전송 계층의 데이터가 호스트에 도착하면 해당 포트에 바인딩한 프로세스가 데이터를 소비할 때까지 버퍼에 머무르게 된다.
    • 호스트에 메모리가 아무리 많아도 버퍼 자체는 고정된 크기로 만들어진다.
  • 느린 CPU에서 돌아가는 복잡한 프로세스가 있으면 데이터를 소비하는 속도가 도착하는 속도를 따라가지 못하는 경우가 생길 수 있다.

    • 버퍼가 곧 가득 차서 추가로 수신되는 데이터가 버려진다.
    • 송신 측 TCP 호스트는 ACK를 받지 못해 버려진 데이터를 빠른 속도로 다시 보내게 된다.
    • 수신 측 호스트는 여전히 느린 CPU이기 때문에 기껏 다시 받은 패킷을 또다시 버릴 것이고 악순환이 계속될 것이다.
    • 엄청난 체증이 유발되어 막대한 인터넷 자원을 낭비하게 된다.
  • 위와 같은 참사를 방지하고자 TCP는 흐름제어(flow control) 기법을 사용한다.

    • 빠른 송신 호스트가 느린 수신호스트를 압도하지 못하게 제어하는 기법
    • 각 TCP 헤더에는 수신 윈도(receive window) 필드가 있어서 패킷을 보낸 호스트의 수신 버퍼 여유량을 기재하게 되어있다.
      • "내가 이만큼의 데이터를 받을 수 있으니 그 이상 보내려면 ACK를 기다렸다가 보내라"라는 의미

    • 이해하기 쉽도록 최대 세그먼트 길이를 100바이트로 설정
    1. 호스트 B는 초기 SYN-ACK 패킷으로 응답하면서 수신 윈도 크기를 300바이트로 통지
      • 호스트 A는 100바이트짜리 세그먼트를 세번 보내고 나면 호스트 B의 ACK를 기다려야 함
    2. 호스트 B가 첫 번째 ACK를 보낼 때, 버퍼에 100바이트를 저장해 놓고 프로세스가 소비하길 기다려야 되므로, 호스트 A에게 수신 윈도를 200바이트로 줄여달라고 요청
      • 호스트 A는 200바이트가 이미 전송중인 걸 알고 있으므로 데이터를 더 보내지 않고 기다린다.
    3. 호스트 B가 두 번째 ACK를 보낼 때, 버퍼의 데이터 중 50 바이트가 소비되었다.
      • 버퍼에 총 150 바이트가 들어있고 나머지 150바이트의 여유가 생김
    4. 이번 ACK를 보낼 때 수신 윈도가 150바이트라고 알려준다.
      • 호스트 A가 이것을 받을 때 아직 100바이트가 전송 중이지만 수신 윈도가 150 바이트가 되었으므로 추가로 50바이트 세그먼트를 호스트 B에 보낸다.
    • 이런식으로 흐름 제어가 계속 되어 호스트 B는 항상 데이터를 받을 수 있는 여유가 얼마나 있는지 호스트 A에게 알려주고 버퍼에 담을 수 있는 이상으로 과도한 데이터를 보내지 못하게 한다.
  • 이론적인 TCP 데이터 스트림의 대역폭 한도 = 수신 윈도 / 왕복 시간

  • 수신 윈도를 너무 작게 잡으면 TCP 송신에 병목 현상이 발생한다.

    • 이를 피하려면 이론상 대역폭 최대치가 호스트 사이 링크 계층의 최대 전송률을 넘어서도록 수신 윈도를 충분히 큰 값으로 잡아야 한다.
  • 위 그림에서 호스트 B가 나중에 연달아 두개의 ACK 패킷을 보냄

    • 이는 대역폭을 효율적으로 사용하지 못하는 예
    • 두번 쨰 ACK 패킷의 ACK 번호가 첫 번째 ACK를 내포하므로 앞의 것은 굳이 필요치 않다.
      • IP 헤더와 TCP 헤더만 합쳐도 40바이트가 낭비
      • 링크 계층 프레임을 고려해보면 더 많은 부분을 낭비
    • 이렇게 비효율적으로 헤더를 낭비하는 것을 줄이고자 TCP에 지연 ACK(delayed acknowledgment)라는 규정을 두었다.
      • TCP 세그먼트를 받는 호스트는 즉각 응답할 필요가 없으며 최대 500밀리초까지 기다려보고 시간 내에 다음 세그먼트가 오지 않는 경우에만 ACK를 보내도 상관 없다.
  • 흐름제어를 통해 TCP가 느린 단말 호스트를 많은 데이터로 압도해 버리는 상황은 막을 수 있지만, 느린 네트워크나 라우터에 과부하가 걸리는 것은 어쩔 수 없다.

    • 불필요하게 네트워크 흐름이 한쪽으로 몰리는 것을 방지하고자 TCP엔 혼잡 제어(congestion control) 기법이 사용된다.
    • 고속도로 진입로에 신호등을 두어 교통량을 통제하는 것과 유사
    • TCP 모듈은 혼잡을 줄이기 위해 ACK 없이 보낼 수 있는 데이터의 한도를 자발적으로 제한.
    • 흐름제어와 비슷한 듯 하지만 수신 측의 윈도 크기에 따르는 것이 아니라, 송신자 자체적으로 패킷의 확인응답률 및 누락율을 집계하여 한도를 정하는 것이 차이점.
    • 대부분 합 증가/ 곱 감소에서 파생된 기법을 사용
      • 이 방식에선 처음 연결을 맺을 때 TCP 모듈의 혼잡 임계치를 최대 세그먼트 길이의 낮은 배수 값으로 잡음
        • 보통 두배 정도로 함
      • 이 후 세그먼트의 ACK를 받을 때마다 임계치를 최대 세그먼트 길이 만큼 더해나간다.
      • 망 속도가 무제한인 연결이 있다고 가정하면 매 왕복 주기마다 임계치에 육박하는 패킷과 ACK를 주고받으면서 임계치는 지속해서 두배씩 늘어나게 된다.
      • 만일 패킷이 하나라도 누락되면 TCP 모듈은 네트워크 혼잡을 우려하여 즉시 임계치를 절반으로 줄여버린다.
      • 이런 식으로 조절해 나가면 점차 적절히 안정된 수치로 수렴하여 체증이로 인해 패킷이 누락되지 않을 만큼의 적당한 빠르기로 패킷을 보낼 수 있게 된다.
    • 패킷의 크기를 최대 세그먼트 길이에 가능한 한 가깝게 맞추어 네트워크 혼잡을 줄이는 기법
      • 각 패킷에 40바이트의 헤더가 붙어야 하므로 작은 세그먼트를 여러 개 보내는 것보다 큰 세그먼트 하나로 합쳐 보내는 편이 훨씬 효율적이다.
      • 합쳐 보내려면 TCP 모듈에 송신 데이터용 버퍼를 설치해서 윗단 계층에서 넘겨주는 데이터를 쌓아둘 필요가 있다.
      • 여러 운영체제에서 **네이글 알고리즘(Nagle's algorithm)**을 적용하여 세그먼트를 보내기 전 데이터를 쌓아두도록 규정한다.
        • 이미 전송 중인(아직 ACK를 받지 못한) 데이터가 있을 때 이후 보낼 예정인 데이터는 쌓아두는데 쌓인 양이 한계치를 넘어서면 그때 세그먼트로 만들어 보낸다.
        • 이때 한계치는 최대 세그먼트 길이나 혼잡 제어 윈도 중 작은 것으로 한다.
        • 최대 세그먼트 길이를 기준으로 데이터를 쌓아두는데 그 크기가 혼잡 제어 임계치를 넘지 못하도록 한다는 의미
      • 네이글 알고리즘은 대역폭은 절약해 주지만 데이터를 보내는데 지연이 훨씬 커지기 때문에 게임에 있어서는 그다지 달갑지 않은 존재이다.
        • 대부분 TCP 모듈에는 혼잡 제어를 아예 끄도록 하는 옵션이 있다.

연결 해제
  • TCP를 종료하려면 양측이 종료 요청 및 응답을 주고 받아야 한다.
  • 연결을 종료하길 원하는 호스트는 FIN 패킷을 보내 데이터 전송이 끝났다는 것을 알린다.
  • 송신용 버퍼에 있는 모든 데이터를 비롯해 FIN 패킷까지 정상적인 절차로 전송하고, ACK를 받을 떄까지 재전송도 통상과 같이 수행한다.
  • 하지만 TCP 모듈은 더 이상 윗단 계층이 주는 데이터를 추가로 보내지 않는다.
  • 상대편 호스트가 보내는 데이터를 받기는 하지만 모두 위에 넘기지 않고 그냥 ACK만 보낸다.
  • 상대편도 그 쪽의 데이터를 다 보낸 뒤엔 마지막으로 FIN을 보낼 것이다.
  • 연결을 해제하려는 호스트가 FIN을 보내어 ACK를 받고 상대 호스트의 FIN도 받으면 비로소 연결이 완전히 종료되어 연결 상태가 모두 삭제된다.
  • ACK를 기다리다가 시간이 초과되면 마찬가지로 연결이 완전히 종료된다.


응용 계층

  • TCP/IP 스택 최상단
  • 게임 코드를 작성할 때 이 곳에 프로그래밍
  • 종단간 통신에 꼭 필요한 여러 인터넷의 기본 프로토콜이 응용 계층에 위치하여 전송 계층과 상호작용


DHCP (Dynamic Host Configuration Protocol)

  • 사설 서브넷 망에 물린 여러 호스트의 고유 IPv4 주소를 일일이 할당하는 것은 관리하기가 너무 힘들다
  • DHCP를 사용하는 경우 기기를 네트워크에 물리기만 하면 DHCP가 설정을 자동으로 관리
  • DHCP 동작
    1. DHCP 클라이언트가 설치된 호스트에 네트워크에 물린다.
    2. DHCP 클라이언트가 호스트의 MAC 주소를 DHCPDISCOVER 메시지에 담아 UDP 주소 255.255.255.255:67에 브로드 캐스트한다.
      • 서브넷 상 모든 호스트에 메시지가 전달됨
    3. 메시지를 받은 호스트들 중 DHCP 서버가 있다면 이 메시지를 받는다.
    4. DHCP 서버에서 새 클라이언트에 할당해 줄 IP 주소가 있다면 DHCP 서버는 UDP 포트 68로 DHCPOFFER 패킷을 브로드 캐스트 한다.
      • 이 패킷에는 할당할 IP 주소와 해당 클라이언트의 MAC 주소가 기재되어 있음
      • 이 시점 까지는 아직 클라이언트에 IP 주소가 할당된 상태가 아니므로 해당 클라이언트에게 패킷을 직접 되돌려 줄 수가 없기 때문에 브로드캐스트를 통해 서브넷 내 전체 호스트에게 전달.
    5. 모든 DHCP 클라이언트들은 해당 패킷을 받고 MAC 주소를 확인한다.
    6. 해당 클라이언트가 패킷을 받게 되면 할당된 IP 주소를 확인하여 이 주소를 받아들일지 결정한다.
    7. 받아 들이는 경우 DHCPREQUEST에 제공된 주소를 담아 다시 브로드캐스트 한다.
    8. 아직 요청에 유효한 경우 DHCP 서버는 다시 브로드캐스트로 DHCPACK 메시지를 보낸다.
      • 이 최종 메시지로 새 클라이언트의 IP가 확정되었음을 알리며, 서브넷 마스크, 라우터 주소, 추천 DNS 서버 경로 등 부가 네트워크 정보도 같이 담아서 보낸다.


DNS (Domain Name Service)

  • 도메인과 서브도메인 네임을 IP 주소로 해석하는데 사용
  • 네임 서버는 여러 도메인 네임에 대응되는 IP 주소 목록을 가지고 있다.
  • 인터넷에는 수천수만 개의 네임 서버가 존재
    • 대부분은 자신이 관할하는 영역의 도메인과 서브 도메인의 주소만 가지고 있다.
    • 자신이 관할하지 않는 도메인을 요청 받으면 그쪽을 관할하는 네임서버로 요청을 계속 전달해가며 찾는다.
    • 한번 찾은 결과는 대개 캐싱해 두어서 다음번에 같은 요청이 또 오게되면 여기저기 물어보지 않고 바로 답해준다.
  • DNS 요청과 응답은 보통 UDP 포트 53으로 주고 받는다.


[리뷰] C#코딩의 기술 기본편 - 길벗

$
0
0

책이 주었던 느낌


책을 처음 받았을 때 생각보다 아담한 사이즈였고 책을 펼쳐보니 대화식의 짤막한 단원들로 구성이 되어 있어서 기본편 답게 가벼운 내용을 다루겠구나라고 생각했었습니다. 하지만 책을 완독하고 난 후에는 기본편이라고만 보기에는 깊은 내용들이 많이 담겨있었고, 실무에서 반드시 필요한 지식들로 가득했습니다. 마치 이펙티브 시리즈를 보는 것 처럼 각 단원마다 버릴 내용이 없었고, 개그 요소를 섞어가며(저자가 일본인이라서 일본식 개그가 많았지만) 딱딱한 주제들을 재미있게 풀어나가는 필력 또한 감탄스러웠습니다.



이 책에는 신입 개발자 느낌의 래머군과 이 래머군이 업무를 진행하면서 생기는 궁금증들에 대해 조언 또는 토론을 진행하는 악마와 천사가 등장합니다. 악마는 악마답게 그럴싸하지만 완벽한 답이 아닌, 또는 잘못된 답을 알려주고 천사가 이를 비판하며 모범답안을 제시합니다. 이러한 진행 과정이 대화체를 통해 이루어지는데 평소에 개발자들과 주고 받았던 대화들과 비슷한 부분들이 많아서 여러모로 공감을 해가며 재미있게 읽을 수 있었습니다.


이렇게 재미 요소를 넣어가며 쉽게 풀어나가다보니 어떤 주제에서는 조금 더 깊게 다뤄주었으면 좋겠는데 언급만 하고 지나가는 경우가 다소 있었습니다. 이런 부분에서는 언급된 내용들을 단초로 검색을 통해 궁금증을 해소할 수 있었습니다. 너무 자세한 내용을 이 책에서 다루게 된다면 흥미가 떨어질 수도 있을 것 같다는 생각에 기본편이라는 타이틀 답게 이 정도 수준이 책에서 다루는 내용으로 적절한 것 같다고 생각을 했습니다.


책의 구성

책의 구성을 살펴보면 먼저 1장에서는 언어 사양 문제를 다루고 있는데, 이는 비단 C#을 위한 내용만은 아니었습니다. 개인적인 생각으로 이 책은 C#이라기 보다는 C 계열의 객체지향 프로그래밍 언어들 중 어떠한 언어를 사용하는 개발자든 읽으면 많은 도움이 될 것이라고 생각을 합니다. 저 또한 최근에는 자바를 더 많이 사용하고 있는데 책을 읽어 나가며 많은 부분에서 도움이 되었습니다.


2장에서는 라이브러리 문제에 대해 다루고 있는데, 가장 C#에 특화된 장이었습니다. 다른 언어들에는 해당되지 않는 내용들이 많았고, 마지막 자바여 편히 잠들라 라는 단원에서는 제목만 보고 C# 추종자 같은 느낌이 들었지만 그런 내용은 아니었고 C#과 자바의 언어적 지향점이 다르다는 것과 언어마다의 특성을 잘 이해해야 한다는 내용이었습니다. 특히 같은 객체지향 언어라고 해서 쉽게 보고 쉽게 구현해낼 수 있다는 생각이 나중에 큰 화를 부를 수 있겠다는 생각을 하였습니다. 사실 얼마전까지만해도 자바스크립트가 자바랑은 다르긴 하지만 금방 배워서 쓸 수 있겠지라는 생각으로 웹개발에 도전했었는데 나름 잘 구현했다고 생각했던 코드에서 의도하지 않았던 동작을 하고 서비스에 악영향을 미치는 것을 보고 언어에 대해서 제대로 알고 사용을 해야겠다는 것을 느꼈었습니다. 대부분의 문제들이 언어에 대해 제대로 이해하지 못하고 사용한 부분에서 발생했었습니다.


3장에서는 개발 환경 문제에 대해 다루고 있는데, GAC이라는 것은 이 책을 통해 처음 알게되었습니다. 글로벌로 참조를 하여 여러 애플리케이션에서 참조할 수 있다니, 좋은 점도 있겠지만 책에서 언급한 것 처럼 많은 주의를 기울여야 할 것 같았습니다. 그리고 버전에 대한 부분에 대해서도 언급을 하는데 실제로 업무를 하면서 자바스크립트의 특정 라이브러리를 사용하다가 최신 버전으로 버전업을 하니 잘 돌아가던 코드에서 오류가 났던 적이 있었습니다. 널리 알려진 단체에서 개발한 라이브러리에서도 버전업을 하면 이전 버전을 사용하던 부분에서 오류가 발생하는 경우가 간혹 있는데, 하물며 인터넷에 떠도는 각종 라이브러리들은 통보도 없이 변경되는 경우가 허다합니다. 그러므로 버전 변경은 꼼꼼한 확인을 통해 이상이 없다는 것을 검증한 후에 사용을 해야합니다.



4장에서는 알고리즘 문제에 대해서 다루고 있는데, 악마가 조언하는 알고리즘들을 보니 자꾸 저를 보는 것 같아 부끄러운 마음이 들기도 하고 웃기기도 했습니다. 읽는 내내 악마를 보면 자기 주관이 없고 이리저리 흔들리는 모습을 보니 자꾸 거울을 보는 듯한 느낌이 들었습니다.



이에 반해 천사의 경우에는 거두절미하고 코드를 보여줘라는 대사와 함께 추측하지 않고 자신이 알고 있는 팩트를 가지고 조리있게 얘기하는 걸 보고 느끼는 부분이 많았습니다.


마지막 5장은 비주얼 스튜디오에 대한 내용이므로 팁이라 생각하고 가볍게 읽어보면 좋을 것 같습니다.


결론

이 책의 장점은 대화체를 사용한다는 점과 이로 인해 처음부터 끝까지 술술 읽힌다는 것입니다. IT 전문서를 읽다보면 처음 의지와는 달리 점점 흥미를 읽고 포기하는 경우가 많은데 이 책은 끝까지 재미있게 읽을 수 있었습니다. 코딩의 기술 시리즈는 C# 실전편이 존재하고, C#외에도 파이썬과 자바편도 있는데 한번씩 읽어보고 싶은 마음이 들었습니다. 현업에 입문한 신입 개발자들이나 개발에 지쳐 잠시 머리를 식히고 싶은 개발자 분들께 이 책을 추천합니다.


[리뷰] 실전 스프링 부트 워크북 - 한빛미디어

$
0
0



책을 펼치며

평소에 스프링에 대한 관심은 가지고 있었지만 사내에서는 서블릿 기반의 웹 서버를 사용하기 때문에 업무에서 사용할 기회가 없어서 깊이 있게 공부하지는 못하고 있었습니다. 또한 스프링을 장애 없이 현업에서 사용하기 위해서는 깊은 이해가 필요한데 팀원 모두가 공부하고 테스트해보고 적용하기까지는 많은 시간을 필요로 했습니다. 이러한 진입장벽 때문에 스프링은 거의 배제한 채로 비교적 Old한 방식의 서블릿 기반 웹서버를 계속해서 사용해오고 있었습니다.


그러던 중 커뮤니티에서 스프링 부트에 대한 세미나를 듣게 되었고, 급 관심이 생기게 되었습니다. 가장 매력적이었던 부분은 스프링에서 복잡했던 xml 파일 작성부분이 스프링 부트에서는 필요가 없다는 것이었습니다. 스프링 부트 웹 페이지에서 원하는 설정들을 체크박스 형태로 선택한 후에 Generate를 수행하면 기본 프로젝트 구성을 알아서 다 해줍니다. 그러므로 설정은 최소화하고 개발자는 개발에만 신경쓸 수 있게끔 해주고 있기 때문에 이 정도면 팀원들을 설득하고 짧은시간 내에 활용할 수 있을 것 같다는 생각이 들었습니다.



이러한 생각을 가지고 설레는 마음으로 실전 스프링 부트 워크북이라는 책을 읽어보게 되었는데, 표지만 봐도 공부를 하고 싶어지는 욕구가 생겼습니다. 그만큼 최근에 나오는 개발 서적들의 표지나 내용물이 점점 더 깔끔하고 눈에 잘 들어오게 변화하고 있는 것 같습니다.



책의 구성

대부분의 기술 서적들과 같이 시작은 스프링 부트가 무엇인지, 그리고 왜 스프링 부트를 사용해야 하는지에 대해 설명을 해주고 있습니다. 스프링과 스프링 부트의 차이가 무엇인지, 그리고 스프링 부트를 사용하면 무엇이 좋은지에 대해 궁금하신 독자들은 이부분에서 궁금증을 해소하실 수 있을 것입니다.



책의 구성은 기본적으로 이론을 설명해주고, 이론을 활용한 코드를 생략 없이 모두 수록하고 있습니다. 그리고 이 코드에 대한 설명을 뒤에 덧붙이면서 독자의 이해를 도와줍니다. 실행에 필요한 전체 코드를 수록하고 있기 때문에 하나씩 따라 쳐 보면서 직접 어플리케이션을 구현해볼 수 있다는 것이 이 책의 장점이라고 생각합니다.


아쉬웠던 점은 책의 대부분이 텍스트로만 이루어져 있었기 때문에 각 애너테이션 간의 관계나 클래스들 간의 관계 등 이론적인 설명들이 머릿속에 잘 그려지지 않았습니다. 그래서 같은 내용을 여러번 반복해서 읽고, 연습장에 클래스 다이어그램이나 그림을 그려가면서 읽어야 했습니다. 또한, 예제에서 사용되는 css와 js 파일이 이 예제의 프로젝트가 아닌 외부의 프로젝트에서 가져온 것이므로 해당 파일들을 직접 다운받아서 프로젝트에 첨부를 시켜주어야 하기 때문에 초반에 정상적으로 서버를 구동하는데 어려움을 겪었었습니다.(스프링 부트를 처음 사용해봐서 어떤 위치에 css와 js파일들을 위치시켜야 하는지 몰라서)


마치며

책에서 스프링 부트에 대한 깊은 내용은 다루고 있지 않지만 예제를 따라해보며 스프링 부트가 이런 것이다라는 것은 분명하게 느낄 수 있게 해준 책이었습니다. 데이터베이스를 사용하는 부분에 있어서도 현재 DBCP를 사용하는 것에 비해 굉장히 편리했고 매력적이었습니다. 데이터베이스나 네트워크, 보안 관련된 모듈들을 각각 신경써야 했던 기존과는 다르게 스프링 부트를 사용하면 일관된 방식으로 사용할 수 있다는 것 또한 큰 장점이라고 생각합니다. 다음 프로젝트에서는 스프링 부트를 사용하여 개발하는 것을 목표로 더 깊이 있게 살펴봐야겠습니다.

ELK에 Search Guard 적용

$
0
0

nginx 인증을 사용하여 사내 직원들에게 kibana에 접속하도록 하고 있던 중 Popit의 Search Guard로 ES, 키바나 인증 구축포스팅을 보고 적용을 하게 되었다. 적용 과정 중 수차례 삽질을 했었기 때문에 조금 더 상세하게 정리를 해보았다.



Elasticsearch에 Search Guard 설치

  1. install 명령

    $ bin/elasticsearch-plugin install -b com.floragunn:search-guard-5:5.5.0-14
    • 버전은 아래 버전표 참고
  2. tools 디렉토리로 이동

    $ cd<Elasticsearch directory>/plugins/search-guard-<version>/tools
  3. install_demo_configuration.sh 실행

    $ ./install_demo_configuration.sh
    • 실행권한이 없는 경우 chmod +x install_demo_configuration.sh
    • 실행 후 truststore, keystore, kirk 인증서 파일이 생성됨
      • <Elasticsearch directory>/config 디렉토리에 생성됨
      • truststore.jks : root CA와 intermediate/signing CA
      • keystore.jks : 노드 인증서(node certificate)
      • install_demo_configuration.sh를 통해 생성된 인증서 파일들은 미리 생성해놓은 키값을 사용하기 때문에 보안에 취약하므로 production 서비스에서 사용할 경우에는 keystore와 truststore를 생성하여 사용할 것을 권장.
  4. elasticsearch 실행

    $ <Elasticsearch directory>/bin/elasticsearch
    • elasticsearch가 실행 된 후 아래 sgadmin 스크립트를 실행 시켜주어야 Search Guard를 사용하기 위해 필요한 데이터들이 elasticsearch에 생성된다.
  5. sgadmin_demo.sh 실행

    $ cd<Elasticsearch directory>/plugins/search-guard-<version>/tools
    $ ./sgadmin_demo.sh
    • 권한 설정이나 SearchGuard에 대한 설정 파일들은 plugins/search-guard-<version>/sgconfig 디렉토리에 생성됨

    • elasticsearch의 설정에 따라 ip와 port가 localhost의 9300이 아닌 경우에는 sgadmin_demo.sh 파일을 수정하여 호스트와 포트를 지정한다.'

      $ <Elasticsearch directory>/plugins/search-guard-5/tools/sgadmin.sh -cn searchguard_demo -h localhost -p 9300 -cd <Elasticsearch directory>/plugins/search-guard-5/sgconfig -ks <Elasticsearch directory>/config/kirk.jks -ts <Elasticsearch directory>/config/truststore.jks -nhnv
  6. https://localhost:9200 으로 접속 확인

    • 인증 요청 팝업이 출력됨. (이 계정 정보는 sgconfig/sg_internal_user.xml에 정의)


    • 인증에 성공하면 아래와 같은 정보가 출력됨

      {
        "name" : "9t6GokQ",
        "cluster_name" : "searchguard_demo",
        "cluster_uuid" : "itfKNEpHTZGSnbMuhj8ZrA",
        "version" : {
          "number" : "5.5.0",
          "build_hash" : "260387d",
          "build_date" : "2017-06-30T23:16:05.735Z",
          "build_snapshot" : false,
          "lucene_version" : "6.6.0"
        },
        "tagline" : "You Know, for Search"
      }

Kibana에 Search Guard 설치

  1. 플러그인 다운로드

    $ wget https://github.com/floragunncom/search-guard-kibana-plugin/releases/download/v5.4.2-3/searchguard-kibana-5.4.2-3.zip
  2. 플러그인 설치

    $ bin/kibana-plugin install file:///usr/share/kibana/temp/searchguard-kibana-5.4.2-3.zip
  3. /etc/kibana/kibana.yml 설정

    elasticsearch.url: "https://localhost:9200"
    
    ... 생략 ...elasticsearch.username: "kibanaserver"elasticsearch.password: "kibanaserver"
    
    ... 생략 ...elasticsearch.ssl.verificationMode: none
    
    ... 생략 ...
    • elasticsearch URL은 이제 https를 사용
    • username과 password는 elasticsearch 쪽에 sgconfig/sg_internal_user.xml 파일에 지정된 계정을 사용
    • 사설 인증서를 사용하지 않으므로 verificationMode는 none으로 설정
  4. http://localhost:5601 (키바나)로 접속


  5. 브랜드 이미지를 변경하고 싶은 경우에는 config/kibana.yml에서 아래 설정 추가

    searchguard.basicauth.login.showbrandimage: true
    searchguard.basicauth.login.brandimage: "이미지 경로"
    searchguard.basicauth.login.title: "로그인을 해주세요."
    searchguard.basicauth.login.subtitle: "서브 타이틀입니다."
  6. 키바나 재시작 후 접속


logstash 설정

  1. logstash.conf 파일 작성

    input {
      stdin {}
    }
    output {
      elasticsearch {
        hosts => "localhost:9200"
        user => logstash
        password => logstash
        ssl => true
        ssl_certificate_verification => false
        truststore => "<logstash path>/config/truststore.jks"
        truststore_password => changeit
        index => "test"
        document_type => "test_doc"
      }
      stdout{
        codec => rubydebug
      }
    }
  • user와 password는 elasticsearch의 Search Guard 플러그인에 등록된 유저 정보
    • 기본적으로 logstash 용으로 계정이 정의되어 있음.
  • ssl 설정을 true로 한 경우 ssl을 사용한다.
  • 인증서 파일을 사용하여 인증 절차를 수행하는 경우 ssl_certificate_verification을 true로 설정한다.
    • 여기서는 인증 절차를 수행하지 않기 때문에 false로 설정
    • true인 경우 truststore에 대한 설정을 해주어야 한다.

보충 설명

사용자 관리

아래에서 사용되는 설정 파일들은 <elasticsearch path>/plugins/search-guard-5/ 하위에 위치함.


사용자 추가

  1. sgconfig/sg_internal_users.yml 파일에 유저 추가

    guest:
      hash: 
      #password is: guest
  2. tools/hash.sh를 사용하여 패스워드 생성

    $ sh hash.sh
    [Password:]
    $2a$12$izzerIN4R.m6nCDNuCPtWOR/6n/LBudgjPLBS1naNptyF2VuUPwfe
  3. 생성된 해쉬코드를 복사하여 sgconfig/sg_internal_users.yml 파일에 추가

    guest:
      hash: $2a$12$izzerIN4R.m6nCDNuCPtWOR/6n/LBudgjPLBS1naNptyF2VuUPwfe#password is: guest
  4. tools/sgadmin_demo.sh 파일을 실행하여 변경된 사항 적용

    $ ./sgadmin_demo.sh


권한 설정

  1. 사용자에 대한 권한 role 이름을 sgconfig/sg_roles_mapping.xml 파일에 설정 하고, role 이름을 기반으로 사용자들을 해당 role에 추가시켜서 다수의 사용자들에게 동일한 role을 지정할 수 있다.

    • 기본적으로 prefix로 sg_가 붙음

    • 위에서 추가한 guest의 경우 sg_guest로 지정

      sg_guest:
        uesrs:
          - guest
  2. sgconfig/sg_roles.xml 파일 수정

    • 위에서 설정한 role 이름에 대한 권한을 지정한다.

    • 여기서는 guest로 들어온 경우 read only 권한을 부여

      sg_guest:
        cluster:
          - UNLIMITEDindices:
          '*':
            '*':
              - READ
    • 대문자로 표시되어 있는 값들은 sgconfig/sg_action_groups.yml 파일에 정의되어 있다.

      • 위에 설정한 READ의 경우 아래와 같이 설정됨

        READ:
          - "indices:data/read*"
          - "indices:admin/mappings/fields/get*"
  3. 변경된 사항을 적용하기 위해 tools/sgadmin_demo.sh 실행

    $ ./sgadmin_demo.sh

elasticsearch.yml 설정

http.host: 0.0.0.0logger._root: DEBUG######## Start Search Guard Demo Configuration ########searchguard.ssl.transport.keystore_filepath: keystore.jkssearchguard.ssl.transport.truststore_filepath: truststore.jkssearchguard.ssl.transport.enforce_hostname_verification: falsesearchguard.ssl.http.enabled: truesearchguard.ssl.http.keystore_filepath: keystore.jkssearchguard.ssl.http.truststore_filepath: truststore.jkssearchguard.authcz.admin_dn:
  - CN=kirk,OU=client,O=client,L=test, C=decluster.name: searchguard_demonetwork.host: 0.0.0.0######## End Search Guard Demo Configuration ########
  • keystore/truststore 를 직접 생성하지 않고 이미 생성되어 있는 것을 사용하는 경우 아래 명령으로 인증 정보 확인

    $ keytool -list -v -keystore kirk.jks
    • install_demo_configuration.sh를 통해 생성된 kirk.jks 파일의 패스워드는 changeit
  • 이 설정 값은 install_demo_configuration.sh 쉘스크립트를 실행하면 자동으로 추가된다.


keystore/truststore 생성

자바에 포함된 보안관련 어플리케이션인 keytool을 사용

  1. keystore 생성 (인증서)

    $ keytool -genkey -alias hive-key -keyalg RSA -keypass changeit -storepass changeit -keystore keystore.jks
  2. 위에서 생성한 keystore.jks 인증서를 server.cer 파일로 내보냄

    $ keytool -export -alias hive-key -storepass changeit -file server.cer -keystore keystore.jks
  3. truststore 파일을 만들고 인증서를 truststore에 추가

    $ keytool -import -v -trustcacerts -file server.cer -keystore truststore.jks -keypass changeit
  4. keystore.jks와 trusstore.jks 생성 완료

    Owner: CN=yongho, OU=vinus, O=server, L=Seoul, ST=Samsung, C=16201
    Issuer: CN=yongho, OU=vinus, O=server, L=Seoul, ST=Samsung, C=16201
    Serial number: 3ee66345
    Valid from: Thu Jul 13 05:27:44 UTC 2017 until: Wed Oct 11 05:27:44 UTC 2017
    Certificate fingerprints:
             MD5:  58:DD:2D:D2:11:93:8C:E4:EF:96:4C:0F:8D:04:52:96
             SHA1: 93:5F:BD:68:04:6C:E6:CC:7A:DC:08:79:0D:EB:B4:C3:69:38:EF:A1
             SHA256: 57:FB:66:40:47:A0:6B:1A:96:4B:91:31:60:6C:51:F7:7E:2B:04:29:9A:EE:EE:8E:AB:5A:23:43:F3:4B:E4:83
             Signature algorithm name: SHA1withDSA
             Version: 3
    
    Extensions:
    
    #1: ObjectId: 2.5.29.14 Criticality=false
    SubjectKeyIdentifier [
    KeyIdentifier [
    0000: 33 4D 88 F3 C9 AC 12 DF   3F 92 1D 96 50 9C 36 2E  3M......?...P.6.
    0010: E4 11 2E 51                                        ...Q
    ]
    ]
    

트러블슈팅

zen_unicast 관련 에러

[2017-07-13T06:04:03,175][ERROR][c.f.s.t.SearchGuardRequestHandler] Error validating headers
[2017-07-13T06:04:03,191][WARN ][o.e.d.z.UnicastZenPing   ] [vOvmwD5] [1] failed send ping to {#zen_unicast_127.0.0.1:9300_0#}{UV7v4BgFTaSO3E3F6Ng2DQ}{127.0.0.1}{127.0.0.1:9300}
java.lang.IllegalStateException: handshake failed with {#zen_unicast_127.0.0.1:9300_0#}{UV7v4BgFTaSO3E3F6Ng2DQ}{127.0.0.1}{127.0.0.1:9300}
        at org.elasticsearch.transport.TransportService.handshake(TransportService.java:386) ~[elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.transport.TransportService.handshake(TransportService.java:353) ~[elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.discovery.zen.UnicastZenPing$PingingRound.getOrConnect(UnicastZenPing.java:401) ~[elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.discovery.zen.UnicastZenPing$3.doRun(UnicastZenPing.java:508) [elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:638) [elasticsearch-5.4.3.jar:5.4.3]
        at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37) [elasticsearch-5.4.3.jar:5.4.3]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_131]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_131]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_131]

  • conf/elasticsearch.yml 설정에서 network.publish_host와 network.bind_host가 모두 설정되어 있는 경우 network.publish_host 설정을 제거하면 해결됨

    cluster.name: myclusternode.master: truenode.data: truediscovery.zen.ping.multicast.enabled: falsenumber_of_nodes : 1minimum_master_nodes: 1path.logs: .node.name: ElasticStack.0.0.0.0# network.publish_host: 0.0.0.0network.bind_host: "0.0.0.0"
    ... 생략 ...
  • 참고


Someone (/172.19.0.8:38490) speaks http plaintext instead of ssl, will close the channel

  • Search Guard 사용 시 http 통신 또한 ssl로 사용하도록 설정해둔 경우 기존에 http를 사용하여 logstash나 kibana를 사용하고 있었기 때문에 이 통신이 https가 아니라는 오류가 출력된다.

  • logstash나 kibana에 https로 통신을 하도록 설정하던가 https 통신을 사용하지 않도록 설정하도록 함.

  • 여기서는 https 통신을 사용하지 않는 것으로 설정

  • conf/elasticsearch.yml 파일 수정

    ... 생략 ...searchguard.ssl.http.enabled: falsesearchguard.ssl.http.keystore_filepath: /usr/share/elasticsearch/config/keystore.jkssearchguard.ssl.http.keystore_password: changeitsearchguard.ssl.http.truststore_filepath: /usr/share/elasticsearch/config/truststore.jkssearchguard.ssl.http.truststore_password: changeit
    ... 생략 ...
    • searchguard.ssl.http.enabled을 false로 설정

Not yet initialized 에러

[2017-07-14T10:23:06,639][INFO ][c.f.s.c.IndexBaseConfigurationRepository] searchguard index does not exist yet, so no need to load config on node startup. Use sgadmin to initialize cluster
[2017-07-14T10:23:06,639][INFO ][o.e.g.GatewayService     ] [9t6GokQ] recovered [0] indices into cluster_state
[2017-07-14T10:23:08,171][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
[2017-07-14T10:23:08,200][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
[2017-07-14T10:23:10,708][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
[2017-07-14T10:23:13,212][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
[2017-07-14T10:23:15,714][ERROR][c.f.s.a.BackendRegistry  ] Not yet initialized (you may need to run sgadmin)
  • 키바나에서 연결 요청을 하는 경우 위와 같은 에러 발생

  • Search Guard 플러그인에 대한 초기 설정이 제대로 이루어지지 않아서 발생하는 에러이다.

  • 이는 sgadmin_demo.sh 실행이 실패했다는 것을 의미한다.

  • 실패한 경우를 보면 아래와 같다.

    $ ./sgadmin_demo.sh
    Search Guard Admin v5
    Will connect to localhost:9300
    ERR: Seems there is no elasticsearch running on localhost:9300 - Will exit
    • 여기서는 elasticsearch에 접속하지 못해서 발생하는 에러였는데 실제로 elasticsearch가 구동 중이지 않거나 host 또는 port가 맞지 않았기 때문에 발생하였다.
    • host와 port가 맞지 않은 경우 sgadmin_demo.sh 파일을 수정하여 호스트와 포트를 지정
  • 정상적인 경우에는 아래와 같은 메시지가 출력된다.

    Search Guard Admin v5
    Will connect to 192.168.10.211:9300 ... done### LICENSE NOTICE Search Guard ###
    
    If you use one or more of the following features in production
    make sure you have a valid Search Guard license
    (See https://floragunn.com/searchguard-validate-license)
    
    * Kibana Multitenancy
    * LDAP authentication/authorization
    * Active Directory authentication/authorization
    * REST Management API
    * JSON Web Token (JWT) authentication/authorization
    * Kerberos authentication/authorization
    * Document- and Fieldlevel Security (DLS/FLS)
    * Auditlogging
    
    In case of any doubt mail to <sales@floragunn.com>###################################
    Contacting elasticsearch cluster 'searchguard_demo' and waitfor YELLOW clusterstate ...
    Clustername: searchguard_demo
    Clusterstate: GREEN
    Number of nodes: 1
    Number of data nodes: 1
    searchguard index does not exists, attempt to create it ... done (auto expand replicas is on)
    Populate config from /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/
    Will update 'config' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_config.yml
       SUCC: Configuration for'config' created or updated
    Will update 'roles' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_roles.yml
       SUCC: Configuration for'roles' created or updated
    Will update 'rolesmapping' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_roles_mapping.yml
       SUCC: Configuration for'rolesmapping' created or updated
    Will update 'internalusers' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_internal_users.yml
       SUCC: Configuration for'internalusers' created or updated
    Will update 'actiongroups' with /home/hive/elk-test/elasticsearch-5.5.0/plugins/search-guard-5/sgconfig/sg_action_groups.yml
       SUCC: Configuration for'actiongroups' created or updated
    Done with success 

참고


HashiCorp 밋업 - 당근마켓에서 Packer와 Vagrant 사용기

$
0
0

발표자

  • nackot
  • 당근마켓

Packer

  • 커스텀 이미지 빌드 도구
    • Base 이미지를 기반으로 타겟 어플리케이션에 필요한 구성을 프로비저닝 완료한 이미지 생성
  • 기존에는 만들어진 이미지를 실행시키고 수정 후 다시 이미지로 생성해서 사용하는 것이 혁신적이었음
    • 이미지 빌드 과정을 재현할 수 없기 때문에 자동화가 어려움
    • 이미지 빌드/삭제를 손수 해야함
    • 이미지가 계속 쌓이기만 하고 지울 수 없는 상태가 됨
  • 패커의 핵심 도구
    • 빌더 / 프로비저너의 조합으로 구성됨
      • 빌더 : 특정 플랫폼의 이미지를 만드는 플러그인
      • 프로비저너 : 프로비저닝을 수행하는 플러그인
        • 실제 Packer가 하는 것은 아니고 쉘 스크립트나, 쉐프, 앤서블과 같은 도구로 프로비저닝
    • AWS뿐만아니라 docker, virtual box 이미지 빌드까지 일관된 방식(빌더와 프로비저너의 조합)으로 이미지 생성
  • 이미지 빌드 특징
    • 프로비저너와 함께 코드로 관리
    • 변경이 있을 때마다 매번 이미지 새로 빌드
    • 변경사항이 모두 저장되기 때문에 재현 가능
    • 코드로 관리되므로 자동화 가능
  • 빌드 과정
    • 인스턴스 및 임시 리소스 생성
  • 단점
    • 모든 과정이 한방에 이루어짐
      • 빌드 시간이 길어짐
      • 빌드 과정에 개입이 불가능
      • 문제가 생기면 롤백하고 처음부터 다시 진행

Vagrant

  • 가상머신의 특정 상태를 만들어주는 도구
  • 구성요소
    • 프로바이더와 프로비저너로 구성
      • 프로바이더 : 결과물을 VM 이미지로 만들어줌
      • 프로비저너는 Packer와 의미가 동일
  • Packer는 코드 업데이트 시 이미지를 제거하고 다시 만들지만 Vagrant는 변경된 부분만 프로비저닝
  • 가상환경은 Packer를 사용하는 환경과 다를 수 있음
    • 이를 위해 vagrant-aws 사용
    • Vagrant AWS 프로바이더
    • VM 대신 AWS 인스턴스가 실행 됨
    • 마지막 커밋이 2016년이라는 문제점
  • Packer의 경우 키 파일까지 생성해서 이미지에 넣어주지만 Vagrant는 환경 변수로 등록해서 사용
  • 라이프사이클 관리가 필요
    • Destroy 하지 안흐면 인스턴스가 AWS상에 그대로 남아잇음
    • 자동적으로 종료하도록 구성하는 것이 좋음
  • Vagrant는 업데이트된 부분만 프로비저닝 하기 때문에 이 과정에서 Packer와 결과물이 달라질 소지가 있음
    • 업데이트 시 제거 후 잘 동작하는지 테스트 필요

당근마켓에서 사용하는 방법

  • 패커를 통해 이미지 빌드 자동화 하고 Vagrant로 동작 테스트
  • 프로덕션에서 잘 사용하고 있음


HashoCorp 밋업 - 레거시 위에서 재현 가능한 환경 구축하기

$
0
0

발표자

  • migrammer
  • 선데이토즈

기존 개발환경

  • IDC로 운영 중
  • 5년정도 운영하다보니 각 서버에안에 어떻게 구성되어 있는지 알 수 없는 상태가 됨
  • 서버마다 환경이 다름
  • 로컬 디버깅의 어려움
    • 망 분리로 인해 원격 디버깅 불가능
    • 사내 Vagrant Box도 시간이 지남에 따라 제대로 동작을 안함
    • 환경 정의가 코드로 되어 있었으면 좋겠다는 생각
  • 다중 테스트 서버의 필요성
    • 환경 구성이 번거로워서 한대의 서버로 다중 테스트를 진행
    • 서버를 찍어 낼 수 있는 무언가가 필요함
  • 버그 발생 시 환경 재현의 어려움
    • Dump 만으로는 버그 발견이 어려움
    • 동일 환경을 찍어낼 수 있는 무언가가 필요함
  • AWS로 인프라 이전 진행
    • HashiCorp 사용

HashCorp

  • 로컬 서버 프로비저닝
    • Vagrant
      • 다중 머신 구동 지원
        • 다중 머신 구동 시 실행 순서에 주의
    • 새로운 환경 구성이 쉬워짐
  • 인프라 프로비저닝
    • 테라폼
      • .tf, .tfvars 등으로 인프라 정의 파일 작성
        • 정의 파일은 파일을 분리해서 모듈화
          • 테라폼의 모듈은 함수와 의미가 비슷
          • 변수를 통해 파일이 분리되어 있어서 접근 가능
      • Terraform plan으로 적용시 변경될 인프라 환경 확인 가능
      • terraform apply로 실제 적용
  • 머신 이미지 생성 자동화
    • Packer
      • 작성된 명세를 기반으로 이미지 생성 후 이미지 id 반환

어려웠던 점

  • 학습 비용이 있었음
  • Terraform에 버그가 있었음
  • 검증해줄 사람이 없었음

나아진점

  • 서버가 클린해짐
  • 인프라 프로비저닝이 편리해짐
  • 인프라 구성이 모두 코드로 남아 추적 용이

남은 문제

  • 협업 시 tfstate, tf 데이터 관리의 어려움
  • 프로덕션에는 아직 적용 안해봄
  • 서버 프로비저닝과 코드 배포 프로세스의 개선 여지가 많음
    • 현재 코드와 인프라 프로비저닝을 함께 하고 있음
    • 이로인해 코드 변경시에 인프라가 재구축됨
    • 배포 프로세스 분리가 필요


HashCorp 밋업 - 데브시스터즈 Valut 사용기

$
0
0

데브시스터즈에서 사용하는 HashiCorp 제품

  • 테라폼
  • Packer
  • Valut

기존 시스템의 문제점

  • 초기에는 모든 팀원이 공용비밀번호와 공용 SSH Key 발급 받아 사용
  • 퇴사자 발생 시 Key Rotate
  • 관리해야할 패스워드가 점점 많아져서 기억하기가 어려워짐
  • 패스워드가 필요한 환경이 많다보니 키교체의 일부 자동화는 가능하지만 완벽한 자동화가 어려움

Valut를 통한 SSH

  • Valut는 SSH 기본 제공 인증서 기반
  • 믿을 수 있는 Secret Store
  • Flow
    • 클라이언트가 SSH Pulbic Key를 통해 Valut CA에 인증 요청
    • Valut는 클라이언트에게 접근 허용을 하고 Expire 시간을 지정
    • 발급 받은 public key로 서버에 접근
    • 서버는 authorized_keys와 대조하여 접근 허용
  • 서버 셋업
    • Valut 명령으로 인증서 생성
    • Valut 명령으로 역할 등록
    • 서버에 공개키 등록
    • Packer로 이미지 생성
  • 클라이언트 접속
    • valut ssh 명령으로 접속
  • 장점
    • 훌륭한 권한 관리 시스템
    • 개인, 그룹 단위의 권한 관리
      • 새로운 인원이 추가되어도 그룹에 넣어주기만 하면 됨
  • Valut 장애 발생을 대비해서 비상용 키를 둠

코드에 적혀있는 Private 정보

  • 보안 문제와 키 변경시 코드를 업데이트해야하는 이슈
  • 작업자가 패스워드를 몰라도 사용할 수 있도록 하는 것이 최선
  • Valut의 Key-Value Store 사용
    • valute read 명령
  • AWS 인스턴스 자격 증명에 대한 문서가 있음
    • Instance-identity/pkcs7
  • Flow
    • EC2 인스턴스가 AWS에서 자격 증명 요청
    • AWS에서 자격증명을 받으면 Valut에 자격증명 문서를 보냄
    • Valut는 AWS에 자격증명 검증을 요청
    • 검증에 통과하면 VALUT_TOKEN을 인스턴스에 전달
  • Packer로 이미지 생성해서 사용했지만 얼마전에 이 역할을 해주는 Valut Agent가 출시됨
  • Valut는 처음 자격증명을 요청한 인스턴스에 nonce값을 전달함. 이 후부터는 이 nonce값을 알아야 접근 가능
    • PKCS를 탈취당해도 nonce 값이 없으면 접근 불가능

안정성

  • Valut 장애에 대비 (고가용성)
    • Valut 서버 두대로 구성 (Active - Stanby)
    • Consul 클러스터 구성
      • Key-Value Store, Service Discovery 등의 역할
      • Valut와 연계가 잘됨
    • 서버 구성은 테라폼을 사용해서 간단하게 구성 됨
  • 무중단 업데이트

보안

  • Secret을 보관하는 장소이기 때문에 무엇보다 안전해야함
  • Valut 권장사항을 필독하고 따르려고 노력함
  • End-to-End TLS
    • ELB는 TCP 로드밸런싱만 제공하고 Valut를 통해 TLS 접근
    • 인증서 관리 문제
      • 각각의 인스턴스에서 알아서 발급 받고 알아서 갱신
        • github.com/Neilpang/acme.sh 사용
      • Route 53을 사용한 인증

사용성

  • 사용자들이 사용 방식의 변화를 크게 느끼지 않도록 하는 것이 중요
  • 문서화
    • Valut가 좋은 도구이지만 클러스터 구축을 해야하고 도입이 어려움
    • 꼼꼼한 문서화가 필요
  • 셋업에 들어가는 시간은 초기에만 들어가지만 이후부터는 권한 설정에 많은 시간을 쓰게 됨
    • 이미 있는 인프라를 사용하는 것이 좋음
      • Github 그룹 또는 LDAP
  • Secret 관리
    • 체계적이고 직관적인 경로 설정
      • ex) /secret/app/appname/rds
    • 정책에 대한 꼼꼼한 문서화

Valut 사용 회고

  • End-to-End TLS와 같은 경우 셋업 난이도가 높음
    • 권장사항을 따르는 것은 좋지만 난이도와 일정 조율 필요
  • 스토리지 백엔드로 Consul을 사용하는데 생각보다 관리가 까다로웠음
    • 버전업을 한번에 성공한 적이 없음
    • 사용 시 적극적인 백업 권장
  • Valut의 최고 장점이자 핵심 가치인 Audit Logging이 굉장히 좋았음
    • Secret 접근에 대한 모든 로그가 남기 때문에 조사하면 다 알 수 있음
  • Valut에 저장할 수 있는 것은 키도 가능하고 설정파일, OPT등등 다양함
    • 일단 넣고 보는 문화가 좋았음
      • Config파일도 Valut에 , OPT는 TOTP Backend에
  • 발전속도가 빠름
  • 자사 제품과 뛰어난 연계
    • Consul
    • Consul Template
    • Terraform
    • Packer
    • Nomad

기타

  • AWS 환경에서만 서비스를 한다면 Secret Manager를 사용해도 좋지만 멀티 프로바이더 지원을 위해서는 Valut 사용이 더 나은 듯
  • Valut는 하나의 클러스터로 구성되어 있고, VPC Peering을 통해 다른 시스템에서 접근
  • 케르베로스, LDAP을 통해 관리하던 분들이 Valut 사용을 검토하고 있음


Viewing all 302 articles
Browse latest View live