git clone https://github.com/deviantony/docker-elk

nginx를 설치하고 docker 기반으로 ELK (elasticsearch, logstash, kibana)를 설치하고 nginx 로그를 filebeat를 설치하여 acces.log, error.log, syslog등을 전송해보자.

 

설치 

ELK를 도커에 설치하는 스크립트를 아래 github에 잘 정리되어 제공해주고 있다.
https://github.com/deviantony/docker-elk

ELK는 이걸로 설치하면 되는데 docker-compose로 nginx와 filebeat까지 함께 설치하기 위해서 아래 저장소에서 제공하는 nginx-filebeat 스크립트를 혼합해서 사용해보자.
https://github.com/spujadas/elk-docker/tree/master/nginx-filebeat

1. 우선 ELK 설치 스크립트를 가져오자.

git clone https://github.com/deviantony/docker-elk



2. 그리고 nginx-filebeat 파일을 다운 받아서 docker-elk 디렉토리 내부에 추가한다.

git clone https://github.com/spujadas/elk-docker
mv ./elk-docker/nginx-filebeat ./docker-elk



3. 그리고 nginx-filebeat까지 사용할 수 있도록 docker-compose.yml 스크립트를 수정해준다. 그리고 nginx.conf 파일을 쉽게 보고 생성된 log도 로컬에서 보기 위해서 mount를 로컬 폴더로 진행한다.

version: '3.2'

services:
  elasticsearch:
    container_name: "elasticsearch"
    build:
      context: elasticsearch/
      args:
        ELK_VERSION: $ELK_VERSION
    volumes:
      - type: bind
        source: ./elasticsearch/config/elasticsearch.yml
        target: /usr/share/elasticsearch/config/elasticsearch.yml
        read_only: true
      - type: volume
        source: elasticsearch
        target: /usr/share/elasticsearch/data
    ports:
      - "9200:9200"
      - "9300:9300"
    environment:
      ES_JAVA_OPTS: "-Xmx256m -Xms256m"
      ELASTIC_PASSWORD: changeme
    networks:
      - mynet

  logstash:
    container_name: "logstash"
    build:
      context: logstash/
      args:
        ELK_VERSION: $ELK_VERSION
    volumes:
      - type: bind
        source: ./logstash/config/logstash.yml
        target: /usr/share/logstash/config/logstash.yml
        read_only: true
      - type: bind
        source: ./logstash/pipeline
        target: /usr/share/logstash/pipeline
        read_only: true
    ports:
      - "5000:5000"
      - "9600:9600"
    environment:
      LS_JAVA_OPTS: "-Xmx256m -Xms256m"
    networks:
      - mynet
    depends_on:
      - elasticsearch

  kibana:
    container_name: "kibana"
    build:
      context: kibana/
      args:
        ELK_VERSION: $ELK_VERSION
    volumes:
      - type: bind
        source: ./kibana/config/kibana.yml
        target: /usr/share/kibana/config/kibana.yml
        read_only: true
    ports:
      - "5601:5601"
    networks:
      - mynet
    depends_on:
      - elasticsearch

  nginx:
    container_name: "nginx"
    build:
      context: nginx-filebeat/
    volumes:
      - type: bind
        source: /Users/we/Documents/docker/nginx
        target: /etc/nginx
      - type: bind
        source: /Users/we/Documents/docker/nginx_log
        target: /var/log
    ports:
      - "8080:80"
    networks:
      - mynet

networks:
  mynet:
    driver: bridge

volumes:
  elasticsearch:

 

4. 마지막으로 filebeat.xml에서 ssl 통신을 하지 않기 때문에 ssl 부분을 제거해준다. (이유는 하단에 나온다.)

output:
  logstash:
    enabled: true
    hosts:
      - logstash:5044
    timeout: 15

filebeat:
  inputs:
    -
      paths:
        - /var/log/syslog
        - /var/log/auth.log
      document_type: syslog
    -
      paths:
        - "/var/log/nginx/*.log"
      document_type: nginx-access

 

5. 그럼 지금까지 수정한 내용을 이용해서 docker-compose up -d 통해 설치 진행해보자. 설치후 제거 하고 싶으면 (docker-compose -v down) 명령어를 통해 제거 할 수 있다.

docker-compose up -d

 

6. 설치가 완료되면 키바나에 접속해서 확인해보면 logstash, elasticsearch, kibana 모두 설치 된 것을 알 수 있다. 초기 계정은 elastic / changeme이다.

ELK와 nginx docker process

7. logstash pipeline을 만들어줘야하는데 kibana에서 management → logstash → pipeline에서 설정해주면된다. 간단하게 5044포트로 받고 nginx_log 인덱스로 넣게 설정한다.

input {
    beats {
        client_inactivity_timeout => 19909
        port => "5044"
        ssl => false
    }
}
filter {
  if [type] == "nginx-access" {
    grok {
      match => { "message" => "%{NGINXACCESS}" }
    }
  }
}
output {
    elasticsearch {
        hosts => ["elasticsearch:9200"]
        index => "nginx_log"
        user => "elastic"
        password => "changeme"
    }
   stdout { codec => rubydebug }
}

 

8. 그럼 filebeat가 정상적으로 동작하는지 확인해보자.

filebeat 실행 상태 확인

/etc/init.d/filebeat status

 

filebeat.xml 기준으로 설정 정상 적용 상태 확인

filebeat test config

 

filebeat.xml에 설정된 output 정상 여부 확인

filebeat test output

filebeat 테스트 결과

위에 테스트를 진행하면 위에 화면처럼 나오는게 나와야 정상이다. 정상적으로 가동된걸 확인했다.

그럼 실제 nginx에서 나온 로그가 filebeat로 수집되어 logstash > elasticsearch로 정상적으로 적재되는지 보자.
localhost:8080에 접속하여 로그 발생시킨 후 filebeat 로그를 확인했는데 왠걸 다음과 같은 오류가 발생했다.

[2019-10-15T06:12:48,844][INFO ][org.logstash.beats.BeatsHandler] [local: 172.28.0.4:5044, remote: 172.28.0.2:55946] Handling exception: org.logstash.beats.BeatsParser$InvalidFrameProtocolException: Invalid Frame Type, received: 1
[2019-10-15T06:12:48,845][WARN ][io.netty.channel.DefaultChannelPipeline] An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.DecoderException: org.logstash.beats.BeatsParser$InvalidFrameProtocolException: Invalid Frame Type, received: 1
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:459) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:392) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.handler.codec.ByteToMessageDecoder.channelInputClosed(ByteToMessageDecoder.java:359) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.handler.codec.ByteToMessageDecoder.channelInactive(ByteToMessageDecoder.java:342) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:245) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.channel.AbstractChannelHandlerContext.access$300(AbstractChannelHandlerContext.java:38) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.channel.AbstractChannelHandlerContext$4.run(AbstractChannelHandlerContext.java:236) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:66) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) [logstash-input-tcp-6.0.3.jar:?]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [logstash-input-tcp-6.0.3.jar:?]
at java.lang.Thread.run(Thread.java:834) [?:?]
Caused by: org.logstash.beats.BeatsParser$InvalidFrameProtocolException: Invalid Frame Type, received: 1
at org.logstash.beats.BeatsParser.decode(BeatsParser.java:92) ~[logstash-input-beats-6.0.0.jar:?]
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489) ~[logstash-input-tcp-6.0.3.jar:?]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428) ~[logstash-input-tcp-6.0.3.jar:?]
... 10 more

이 문제는 logStash 또는 filebeat가 동시에 ssl을 사용하지 않는데 한쪽만 ssl 통신을 했을 때 발생되는 오류이다.

그래서 아까 위에 filebeat에 ssl 부문을 지우고 pipeline에 ssl 설정을 false로 지정한 것이다. 그럼 다시한번 localhost:8080에 들어가보자.

지금은 index.html을 만들어 놓지 않아서 404 에러가 발생된다.

GET nginx_log/_search
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "nginx_log",
        "_type" : "_doc",
        "_id" : "vc04zm0BZBO8vgBrBmV7",
        "_score" : 1.0,
        "_source" : {
          "ecs" : {
            "version" : "1.1.0"
          },
          "@version" : "1",
          "tags" : [
            "beats_input_codec_plain_applied"
          ],
          "message" : """2019/10/15 07:00:31 [error] 25#25: *16 "/etc/nginx/html/index.html" is not found (2: No such file or directory), client: 172.28.0.1, server: , request: "GET / HTTP/1.1", host: "localhost:8080"""",
          "host" : {
            "name" : "a31d3333d22b"
          },
          "agent" : {
            "type" : "filebeat",
            "version" : "7.4.0",
            "hostname" : "a31d3333d22b",
            "id" : "cc4eb582-e09c-4a83-bb2e-9721c39ee508",
            "ephemeral_id" : "a5918a0b-4688-458f-bbc2-4eb49a3fff03"
          },
          "log" : {
            "file" : {
              "path" : "/var/log/nginx/error.log"
            },
            "offset" : 8524
          },
          "@timestamp" : "2019-10-15T07:00:38.443Z"
        }
      },
      {
        "_index" : "nginx_log",
        "_type" : "_doc",
        "_id" : "vs04zm0BZBO8vgBrBmV8",
        "_score" : 1.0,
        "_source" : {
          "ecs" : {
            "version" : "1.1.0"
          },
          "@version" : "1",
          "tags" : [
            "beats_input_codec_plain_applied"
          ],
          "message" : """172.28.0.1 - - [15/Oct/2019:07:00:31 +0000] "GET / HTTP/1.1" 404 555 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"""",
          "host" : {
            "name" : "a31d3333d22b"
          },
          "agent" : {
            "type" : "filebeat",
            "version" : "7.4.0",
            "hostname" : "a31d3333d22b",
            "id" : "cc4eb582-e09c-4a83-bb2e-9721c39ee508",
            "ephemeral_id" : "a5918a0b-4688-458f-bbc2-4eb49a3fff03"
          },
          "log" : {
            "file" : {
              "path" : "/var/log/nginx/access.log"
            },
            "offset" : 8528
          },
          "@timestamp" : "2019-10-15T07:00:38.443Z"
        }
      }
    ]
  }
}

 

정상적으로 적재가 잘되는것을 확인할 수 있다.

이로써 docker로 구성된 elk로 로그 적재를 진행해봤다. 

 

관련 패키지는 github에 올려놓았다.

https://github.com/weduls/elk_with_nginx

저번 글에서 기본적인 쿠버네티스 관련 개념과 자원에 대해 공부했다.

이제 실질적으로 api애플리케이션을 하나 만들어보고 배포까지 진행해보자.

 

로컬 이미지를 담을 registry 생성

쿠버네티스의 노드들은 외부와 연결되는 경우도 있지만 그렇지 못하는 환경도 많이 존재한다. 그럴 경우 이미지를 내려받을 수 없고 로컬에서만 만들어서 사용할 이미지를 등록할 registry가 필요하다.

# registry 이미지 가져오기
docker pull registry:latest

# 레지스트리 실행
docker run --name MyPrivateRegistry -d -p 5000:5000 registry

 

애플리케이션 생성

우선 spring boot gradle 프로젝트로 아무것도 만들지 않고 바로 빌드해서 사용해보자. 그 이유는 나중에 컨트롤러를 추가해서 엔드포인트가 늘어난 api로 이미지 버전을 변경해서 Rolling update 배포가 되는 것을 확인해보기 위해서이다.

그럼 만들어진 스프링 부트파일을 빌드하는 Dockerfile을 만들어보자.

FROM openjdk:8
ENV APP_HOME=/usr/app/
WORKDIR $APP_HOME
COPY ./build/libs/* ./app.jar
EXPOSE 8080
CMD ["java","-Dspring.profiles.active=development","-jar","app.jar"]

그리고 빌드를 진행하고 registry에 등록해놓자.

# 이미지 빌드 v1 tag
docker build -t demo/api:v1 .
docker image tag demo/api:v1 localhost:5000/demo/api:v1

# registry에 등록
docker image push localhost:5000/demo/api:v1

그리고 registry에서 해당 내용을 확인해보면 정상적으로 등록된 것을 알 수있다. http://localhost:5000/v2/_catalog

 

 

로드밸런서 서비스 실행

서비스의 경우 pod들의 외부와 통신을 담당한다는걸 저번시간에 공부로 알게되었다. 이제 pod를 배포하기전에 배포된 api 컨테이너들을 적절하게 로드밸런싱 해줄 서비스를 동작시켜보자. 

# node-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: node-svc
spec:
  selector:
    app: demo
  ports:
    - port: 80
      protocol: TCP
      targetPort: 8080
  type: LoadBalancer

v1 버전의 node-svc이름을 가지고 있고 demo 애플리케이션에 적용이 되며 tcp프로토콜을 가지고 타겟 포트가 8080을 가지고 있다.

kubectl create -f node-svc.yaml

지금은 endpoints에 아무것도 없다. 왜냐하면 아직 이 로드밸런서에 연결된 pods가 없기 때문이다. 그럼 이제 pods를 배포해서 연결해보자.

 

Pod 배포 (deployment)

그럼 pods를 배포해보자. 이미지는 아까 registry에 적용했던 api를 사용하고 버전은 우선 v1을 사용해보자.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-api
  labels:
    app: demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
      - name: demo-api
        image: localhost:5000/demo/api:v1
        ports:
        - containerPort: 8080

그리고 로드밸런서 서비스를 보면 정상적으로 엔드포인트가 보이는걸 알 수있다.

그럼 minikube ip와 NodePort를 사용해서 한번 api에 붙어보자.

Minikube ip:nodeport

아무것도 만들지 않아서 whitelabel error가 발생한다. 

 

 

Rolling update pod교체

그럼 엔드포인트를 하나 만들어서 새로 image를 넣어보자.

@RestController
@RequestMapping("")
public class DemoController {

    @GetMapping("/test")
    public ResponseEntity test() {
        return ResponseEntity.ok("test");
    }
}

그리고 엔드포인트를 추가하고 나서 새로 이미지를 만들어준다.

docker build -t demo/api:latest .
docker image tag demo/api:latest localhost:5000/demo/api:latest
docker image push localhost:5000/demo/api:latest

그리고 deployments에 있는 demo-api 컨테이너의 api를 바꿔줘보자.

kubectl set image deployments/demo-api demo-api=localhost:5000/demo/api:v1
→ kubectl set image deplyments/{deployments 이름} {container 이름}={새로운 이미지}

그럼 이전 pod들이 꺼지고 새로운 이미지가 적용된 파드로 대체되는걸 볼 수 있다.

변경된 image가 잘 적용이 되었는지 확인해보면 잘나오는걸 확인할 수 있다.

 

굳굳 이렇게 쿠버네티스를 공부하고 실질적으로 한번 배포해봤다. 이제 이걸 wedul timeline에 한번 적용해보면서 더 운영을 해봐야겠다.

  1. Favicon of https://lascrea.tistory.com BlogIcon Lascrea 2019.09.17 21:56 신고

    기본적으로 Deployment는 Rolling Update를 사용하는걸로 알고 있어요!

    • Favicon of https://wedul.site BlogIcon 위들 wedul 2019.09.18 07:18 신고

      아하. 제가 잘못알고 있었네요! 감사합니다. 수정하였습니다

  2. 2019.09.18 11:25

    비밀댓글입니다

docker를 사용하면서 그 편리함을 느끼고 있었다. 그리고 요 근래 it회사에서 docker와 kubernets를 이용하여 인프라를 운영을 하는 것을 많이 들었다.

나는 그런 환경을 접해보지는 못했기 때문에 정확하게 kuberntes가 무엇인지 잘 모른다. 그래서 이번 기회에 kubernets(이하 쿠버네티스)에 대한 기본 개념을 정리하고 설치해서 공부를 위한 초석을 닦아보자.

 

쿠버네티스 (kubernetes)

쿠버네티스는 도커 컨테이너 운영을 자동화 하기위한 오케스트레이션 도구이다. 구글에서 만들었으며 컨테이너를 운영하고 다루기 위한 api와 cli등을 제공한다. 컨테이너 배포 이외에도 효율적인 컨테이너 배치 및 스케일링, 로드밸런싱, 헬스 체크, secure등의 기능을 제공한다.

AWS ECS 와 GClound에서 도커 관리 기능을 제공하면서 컨테이너를 사용한 애플리케이션 개발이 점차 보급 되었다.  기존에도 docker에 스웜(swarm)이라는 기능이 있었으나 사용해 봤을 때 불편한 점이 많았는데 쿠버네티스가 더 편리하게 이 점이 보완되었다. 

 

쿠버네티스 설치 (MacOs)

실습을 진행할 컴퓨터가 mac os이기 때문에 mac에서 설치하는 방법을 알아보자. 우선 docker에서 preference에 들어가면 kubernetes 탭이 존재한다. 여기서 아래와 같이 체크하고 Apply를 누르면 설정이 우선 완료된다.

그리고 cli로 쿠버네티스를 다루기 위한 도구인 kubectl을 설치한다.

curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl
chmod +x kubectl
mv kubectl /usr/local/bin

위에 명령어를 통해 kubectl을 명령어로 등록해주는데 자세한 방법은 홈페이지에 잘 나와있다.

https://kubernetes.io/docs/tasks/tools/install-kubectl/

설치가 완료된 후 버전을 확인해보면 출력되면 정상적으로 설치가 된 것 이다.

 

단일 노드 쿠버네티스 클러스터 Minikube 설치

쿠버네티스 클러스터에는 여러 노드들이 존재하지만 실습을 위해서 단일 노드로 되어 있는 Minikube를 설치해서 사용한다. 맥 기준으로 brew로 설치하면 되고 자세한 방법은 아래를 참조하면 된다.

brew cask install minikube

https://kubernetes.io/ko/docs/tasks/tools/install-minikube/

 

쿠버네티스 구성요소

쿠버네티스로 실행되는 애플리케이션은 노드, 네임스페이스, 파드, 레플리카세트, 디플로이먼트 등 다양한 리소스가 함께 연동해 동작한다. 

그 구성 요소들에 대해 간단하게 정리해보자.

1. 노드

-> 노드는 쿠버네티스 클러스터의 관리 대상으로 등록된 도커 호스트로 컨테이너가 배치되는 대상이다. 노드는 마스터와 일반 노드들로 구성되는데 쿠버네티스 클러스터 전체를 관리하는 서버에는 마스터가 적어도 하나 이상 있어야 한다. 마스터는 클러스터를 상호 조정하는 장치이고 노드는 애플리케이션이 실제로 돌아가는 곳이다. 노드에는 여러 파드들이 위치할 수 있고 그 파드에는 컨테이너들이 존재한다.

구글 이미지 출처

또한 쿠버네티스는 노드의 리소스 사용 현황 및 배치 전략을 근거로 컨테이너를 적절하게 배치한다. 클러스터에 배치된 노드 수, 노드의 사양 등에 따라서 노드에 배치할 수 있는 컨테이너의 수를 결정한다. 클러스터의 처리 능력은 노드에 의해서 결정된다.

kubectl get nodes

 

 현재 노드는 아까 설치한 단일 노드 Minikubes가 마스터로 위치해 있는 걸 볼 수 있다.

 

2. 네임스페이스

쿠버네티스 클러스터 내부에는 여러개의 가상 클러스터를 만들 수 있는데 이 네임스페이스는 하나의 공간으로써 사람또는 상황에 따라서 나눠서 사용할 수 있다. 기본적으로는 default로 되어있다.

 

3. 파드 (pod)

 pod는 컨테이너가 모인 집합체로써 하나 이상의 컨테이너로 이루어 진다. nginx, was처럼 서로간의 연결고리가 있는 컨테이너들은 하나로 묶어 일괄배포한다. pod는 노드내에 배치되고 같은 파드는 여러 노드에 배치할 수도 있고 한 노드에 여러개 배치할 수도 있다. pod는 하나 또는 그 이상의 애플리케이션 컨테이너 그룹을 나타내는 쿠버네티스의 추상적 개념으로 컨테이너에 대해 서로 자원을 공유한다.

  • 볼륨과 같은 공유 스토리지
  • 클러스터 IP 주소와 같은 네트워킹
  • 컨테이너 이미지 버전 또는 사용할 특정포트와 같은 각 컨테이너가 동작하는 방식에 대한 정보

 

apiVersion: v1
kind: Pod
metadata:
  name: sample-echo
spec:
  containers:
  - name: nginx
    image: ddd/nginx:latest
    env:
    - name: BACKEND_HOST
      value: localhost:8080
    ports:
    - containerPort: 80
  - name: echo
    image: dd/echo:latest
    ports:
    - containerPort: 8080
    
 # 파드 yaml 예제

 

4. 레플리카 세트

파드를 하나만 사용하여 가동할 경우에 실제 가용성이 떨어지기 때문에 레플리카 세트를 만들어서 여러 파드를 함께 구성해준 것이다.

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: echo
  labels:
    app: echo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: echo
  template: # template하단은 pad.yaml과 같음

 

5. 서비스 (servce, svc)

서비스를 이용해서 각 Pod에 있는 애플리케이션을 외부에서 접근하게 할 수있다.

쿠버네티스에서 서비스는 하나의 논리적인 파드 셋과 그 파드들에 대한 접근할 수 있는 정책을 정의하는 추상적인 개념이다. 서비스는 종속적인 파드들 사이를 느슨하게 결합되도록 도와준다. 서비스는 모든 쿠버네티스 오브젝트들과 같이 yaml로써 정의 할 수있다. 각 서비스가 되는 대상을 labelSelector를 통해 지정할 수 있다.

각 파드들이 고유의 IP를 갖고 있기는 하지만, 그 IP들은 서비스의 도움없이 클러스터의 외부로 노출될 수 없다. 서비스들은 애플리케이션들에 트래픽이 실릴 수 있도록 허용해준다. 서비스들은 ServiceSpec에서 type을 지정함으로써 다양한 방식들로 노출시킬 수 있다.

clusterIp(기본값) - 클러스터 내에서 내부 IP에 대해 서비스를 노출해준다. 이 방식은 오직 클러스터 내에서만 서비스가 접근될 수 있도록 해준다.

NodePort - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출시켜준다.
<NodeIP>:<NodePort>를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해준다. CluserIP의 상위 집합이다.

LoadBalancer - (지원 가능한 경우) 기존 클라우드에서 외부용 로드밸런서를 생성하고 서비스에 고정된 공인 IP를 할당해준다. NodePort의 상위 집합이다.

ExternalName - 이름으로 CNAME 레코드를 반환함으로써 임의의 이름(스펙에서 externalName으로 명시)을 이용하여 서비스를 노출시켜준다. 프록시는 사용되지 않는다. 이 방식은 kube-dns 버전 1.7 이상에서 지원 가능하다.

 

6. 디플로이먼트 (deployment)

서비스, 파드, 레플리카세트의 집합체로써 애플리케이션의 기초가 되는 단위이다. 디플로이먼트 내부에는 서비스, 파드, 레플리카세트 등을 한번에 구성하여 적용 시킬 수 있다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo
  labels:
    app: echo
spec:
  replicas: 3
  selector:
    matchLabels
      app: echo
  template: # template는 pod와 동일

 

서비스와 디플로이먼트에 차이는 서비스는 내부에 여러 pod들을 외부와 연결해주는 역할을 담당하고 디플로이먼트는 쿠버네티스에서 돌아가는 pod들의 상태를 확인하면서 재시작 등등을 진행하는 담당을 한다.

다음 시간에는 실제 애플리케이션 하나를 이미지로 빌드하고 그것을 minikube에 디플로이먼트를 통해 파드로 배포를 진행해본다. 그리고 스케일적용과 이미지 변경 시 자동으로 새로 배포되는 블루그린 배포도 적용해보자.

 

참고 싸이트

https://kubernetes.io/ko/docs/tasks/administer-cluster/highly-available-master/
https://kubernetes.io/ko/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/
https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/labels/
https://devopscube.com/kubernetes-deployment-tutorial/

와이프가 결혼전에 집에서 사용하던 노트북 lenovo 제품이 있어서 이걸 간단하게 사용할 서버로 쓰고 싶었다.

그래서 우분투를 설치하려고 하는데 계속 the 'grub-efi-amd64-signed' package failed to install into /target/. Without the GRUB boot loader, the installed system will not boot. 라는 오류만 발생했다.

구글링을 하면서 efl boot 영역을 설정해주고 별짓 을 다해도 안되었는데

 

오늘 아침에 이 유튜브를 보고 해결했다. 나중을 위해서 공유해논다.

https://www.youtube.com/watch?v=DWlB0_f3GAY

혼자 공부를 집에서 어떻게 하면 효율적일까 고민을 많이했다.

집에서 주구장창 책을 읽고 해보면 스킬이 늘까? 그렇게 해봤지만 그게 정답은 아니었다. 남들에게는 모르겠으나 나에게는 아니었다. 

 

회사에서 하는 업무는 한정적이니 내가 회사에서 하지 못하지만 알고 싶고 잊고 싶지 않은 내용에 대해서 프로그램을 직접 만들면서 공부할 내용을 정리하고 싶었다.

그래서 만들게 된게 타임라인인데, 개발자 채용정보나 기술 블로그를 rss등을 사용해서 모아볼 수는 있으나 별도의 관리 툴이나 브라우저에서 확인해야해서 좀 불편했다. 그래서 그것을 한번에 볼수 있게 하는 사이트가 있으면 좋을 것 같아서 만들어봤다.

우선 주소는 http://wedul.space이다. aws에 도입하고 싶었으나 비용도 걱정되니해서 집에있는 간이 서버에 도입하였다.

화면은 잘 그릴지 몰라서 vue.js 책을 사서 간단하게 읽고 구성했다.

 

홈 / JOB / TECH로 페이지는 구성되어 있고 앞으로 로그인하여 본인이 구독하고 싶은 회사만 보는 기능을 추가할 예정이다. 그리고 자세히보기 누르면 현재는 해당 페이지로 이동하지만 timeline 내부에서 볼 수 있는 페이지를 추가할 예정이다.

 

원래는 혼자 저 정도 까지 구성하다가 크롤링 사이트를 확장하는데 혼자하기에는 조금 역부족이고 함께하고 하고자 하는 친구가 있어서 요청했다. 그래서 테크쪽과 프론트는 그 친구가 담당해주고 있다. 

저장소는 공개 되어있고 참여하고 싶으신 분들은 pull-request 보내주셔도 좋다.

https://github.com/weggdul/timeline

 

 

백엔드 구성


아무래도 나는 백엔드 개발자이다 보니 백엔드에만 사실 집중했다. 크롤링 양이 많지 않아서 별도 배치를 만들거나 큐에 쌓거나 할 필요는 없었으나 공부를 위해서 모두 구성해봤다.

우선 java8, spring-boot2.1.5로 구성되어 있고 멀티모듈로 관리하고 있다. (https://github.com/weggdul/timeline)

api 서버는 spring-batch를 통해 긁어온 데이터가 쌓여있는 mariadb에서 정보를 가져와 보여주며 중간에 redis가 위치해 있어 데이터를 캐시하고 있다.

 

batch 서버는 spring-batch에서 하루 두번 모든 JOB, tech사이트에 들러 크롤링해오고 그 정보를 kafka로 전송한다. kafka를 리스닝 하고 있다가 kafka에 데이터가 들어오면 읽어서 mariadb로 적재시키고 있다.

 

아직 미완 단계지만 다 만들어지고 나면 배포 자동 구성도 하고 seo도 달고 광고도 한번 달아봐야겠다.

공부도 확실히 되는거 같고.. 연말까지는 하고자 했던거 다 붙여보자.

  1. 지나가는개발자 2019.08.19 14:19

    토이프로젝트 깃 주소도 그렇고 서비스주소도 없다고뜨네요?

    • Favicon of https://wedul.site BlogIcon 위들 wedul 2019.08.19 14:26 신고

      안녕하세요. 주소 정보는 아래와 같구요. 다시한번 확인해주세요!

      서비스 사이트 : http://wedul.space
      github : https://github.com/weggdul/timeline

+ Recent posts