카테고리 보관물: docker

Boot2Docker Volume Disk Resize

Boot2Docker에서 “장치에 남은 공간 없음” 오류가 발생합니까?

많은 수의 이미지와 함께 Boot2Docker를 사용하거나 작업 중인 이미지가 매우 큰 경우 Boot2Docker VM의 볼륨 공간이 부족하면 문제가 발생할 수 있습니다. 솔루션은 먼저 볼륨을 복제한 다음 디스크 파티셔닝 도구를 사용하여 크기를 조정하여 볼륨 크기를 늘리는 것입니다. (GParted)[ http://gparted.sourceforge.net/download.php/index.php ]는 무료 ISO이고 VirtualBox와 잘 작동하기 때문에 사용하겠습니다.

1. Boot2Docker의 VM을 중지합니다.

$ boot2docker stop 

Boot2Docker는 VirtualBox의 기본 도구로 크기를 조정할 수 없는 VMDK 이미지와 함께 제공됩니다. 대신 VDI 볼륨을 만들고 VMDK 볼륨을 여기에 복제합니다.

2. VirtualBox 명령줄 도구를 사용하여 VMDK 이미지를 VDI 이미지로 복제합니다.

$ vboxmanage clonehd /full/path/to/boot2docker-hd.vmdk /full/path/to/<newVDIimage>.vdi —format VDI —variant Standard

3. 필요에 적합한 크기를 선택하여 새 복제 볼륨의 크기를 조정합니다. 많은 컨테이너를 회전하거나 컨테이너가 특히 큰 경우 더 큰 것이 좋습니다.

$ vboxmanage modifyhd /full/path/to/<newVDIimage>.vdi —resize <size in MB>

4. (GParted)[ http://gparted.sourceforge.net/download.php/ ] 와 같은 디스크 파티션 도구 ISO를 다운로드합니다 . Boot2Docker VM의 IDE 버스에 ISO를 추가합니다. ISO를 추가하기 전에 버스를 생성해야 할 수도 있습니다.

5. VirtualBox의 Boot2Docker 이미지에 새 VDI 이미지를 추가합니다.

6. Boot2Docker VM에 대한 설정에서 CD/DVD가 부팅 순서 목록 의 맨 위에 있는지 확인 합니다.

7. VirtualBox에서 Boot2Docker VM을 시작하면 디스크 파티션 ISO가 시작됩니다. 

GParted를 사용하여 GParted Live(기본 설정) 옵션을 선택합니다. 기본 키보드, 언어 및 XWindows 설정을 선택하면 GParted 도구가 시작되고 생성한 새 VDI 볼륨이 표시됩니다. VDI를 마우스 오른쪽 버튼으로 클릭하고 크기 조정/이동 을 선택합니다 . 볼륨을 나타내는 슬라이더를 최대 크기로 끌어 크기 조정/이동 을 클릭 한 다음 적용 을 클릭 합니다. GParted를 종료하고 VM을 종료합니다. VirtualBox의 Boot2Docker VM용 IDE 컨트롤러에서 GParted ISO를 제거합니다.

8. VirtualBox에서 또는 명령줄( boot2docker start)을 사용하여 Boot2Docker VM을 시작하여 볼륨 변경 사항이 적용되었는지 확인합니다.

Docker로 Hadoop 테스트 환경 구축하기 – HDFS

Docker와 테스트 환경

Docker는 애플리케이션을 컨테이너화해서 이미지로 만들어 배치하고 실행할 수 있는 환경을 제공하는 컨테이너 도구1이다.
격리된 파일 시스템을 갖는 컨테이너 특성 덕분에, 운영 환경에 대한 프로비져닝 뿐만 아니라 Docker가 설치된 환경에서 컨테이너화된 애플리케이션을 즉시 구동시켜서 테스트할 수 있는 환경을 구성하는데에도 유용하게 쓰인다.

오픈소스를 포함한 다양한 애플리케이션을 로컬 환경에 설치하고 구성하면서 테스트하다보면(주로 개발자의 노트북), 어느새 로컬 환경은 지저분해지고 몇 해 전에 설치한 애플리케이션이 자동 재시작되어 리소스를 점유하게 된다. 환경 설정 파일은 언제 어떻게 바꿨는지도 모른다. VM 환경으로 OS를 완전히 격리시켜 구성하자니 구동하는데 시간이 오래 걸리고 구동한 이후 점유하는 리소스가 노트북이 감당하기에는 참 크다.

Docker는 이런 환경에서 최적의 도구이다. 컨테이너를 어떻게 구성할지 애플리케이션마다 설정 파일을 생성하고, 서로 상호작용하는 애플리케이션인 경우 다시 실행과 관련된 설정 파일을 생성해서 여러 개의 애플리케이션을 순식간에 실행하고 다시 종료시킬 수 있다.

이 포스트에서는 Hadoop HDFS를 Docker로 컨테이너화 헤서 로컬에 테스트 환경으로 구성하는 방법을 설명한다.

HDFS

하둡 분산 파일 시스템(HDFS)은 마스터 노드인 NameNode와 워커 노드인 DataNode로 이루어져있다. 각각 JVM 위에서 동작하는 자바 애플리케이션으로, 두 애플리케이션만 동작을 하면 HDFS를 구성해서 읽고 쓸 수 있다.
실행 환경은 일반적은 GNU/Linux 그리고 Windows 환경을 지원하며, Hadoop 2.7~2.x2 버전은 Java 7, 8을 지원한다.3

클라이언트에서 각 애플리케이션과 직접 통신하는 포트 정보는 다음 표와 같다.

애플리케이션 기본포트 프로토콜 상세설명 관련 설정 항목
NameNode 50070 HTTP HDFS 상태 및 파일 시스템 조회용 Web UI dfs.http.address
9000 IPC 파일 시스템 메타데이터 관련 작업용 fs.defaultFS
DataNode 50075 HTTP 상태 및 로그 조회용 Web UI dfs.datanode.http.address
50010 TCP 데이터 전송 dfs.datanode.address
표 1. 클라이언트에서 HDFS와 직접 통신할 때 사용하는 포트 정보

이 자료들을 가지고 이제 본격적으로 Docker 컨테이너화를 진행해보자.

Dockerize

애플리케이션을 Docker에서 사용하는 설정 파일인 Dockerfile 양식에 맞게 구성한다. 이 설정 파일이 있으면 Docker 이미지 빌드가 가능하고, 생성한 이미지를 어디에서든 당겨와서(pull) 실행할 수 있다.

사실 이미지를 생성하는 것은 이 설정 파일 없이 직접 기반이 되는 OS 이미지로부터 컨테이너를 실행해서 쉘로 접속, 필요한 작업을 하고 이미지를 커밋해도 된다.
하지만 이 방식은 다음과 같은 문제점이 있다:

  • 이미지가 어떻게 생성되었는지 기록이 남지 않음
  • 따라서 작업한 내용을 다시 되돌리거나, 몇 가지 설정을 변경해서 새로운 이미지를 생성하기 어려움
  • 그리고 생성된 이미지를 신뢰하기 어려움. 따라서 다른 사람과 공유하는데에도 적합하지 않음

블록을 쌓아 올리듯 이미지를 만드는 Docker 세계에서는, 처음에는 조금 번거로워 보이더라도 Dockerfile로 이미지를 만드는 것에 익숙해지는 것이 좋다.

Base

NameNode 이미지를 만들기 전에, 먼저 각 컴포넌트의 밑바탕이 되는 이미지를 구성한다. 밑바탕 이미지는 다음과 같은 내용을 포함헤야 할 것이다.

  • Hadoop binary
  • Java
  • Common configurations

여기에서는 현재 2019년 8월 기준 Hadoop 2버전의 최신 버전인 2.9.2 버전을 사용했다. Hadoop 2는 Java 7 이상을 지원하므로 Java 8을 선택했다. 마지막으로 공용 설정은 core-site.xml, hdfs-site.xml을 포함하도록 구성할 것이다.

먼저 다음과 같은 디렉토리 구조로 폴더와 파일을 생성한다.

.
└── hadoop
    ├── base
    │   ├── Dockerfile
    │   └── core-site.xml
    ├── namenode
    │   ├── Dockerfile
    │   ├── hdfs-site.xml
    │   └── start.sh
    └── datanode
        ├── Dockerfile
        ├── hdfs-site.xml
        └── start.sh

hadoop의 하위 폴더인 base, namenode, 그리고 datanode 폴더와 그 하위에 다시 위치한 개별 Dockerfile은 각 항목이 이미지로 빌드될 것임을 보여준다.

baes/Dockerfile의 내용을 다음과 같이 작성한다.

# 기반이 되는 이미지를 설정. 여기서는 ubuntu 18 기반인 zulu의 openjdk 8버전을 선택
FROM azul/zulu-openjdk:8

# 바이너리를 내려받기 위해 설치
RUN apt-get update && apt-get install -y curl 

ENV HADOOP_VERSION=2.9.2
ENV HADOOP_URL=http://mirror.apache-kr.org/hadoop/common/hadoop-$HADOOP_VERSION/hadoop-$HADOOP_VERSION.tar.gz

# Hadoop 2.9.2 버전을 내려받고 /opt/hadoop에 압축 해제
RUN curl -fSL "$HADOOP_URL" -o /tmp/hadoop.tar.gz \
    && tar -xvf /tmp/hadoop.tar.gz -C /opt/ \
    && rm /tmp/hadoop.tar.gz

# 데이터 디렉토리 생성 및 설정 폴더의 심볼릭 링크 생성
RUN ln -s /opt/hadoop-$HADOOP_VERSION /opt/hadoop \
    && mkdir /opt/hadoop/dfs \
    && ln -s /opt/hadoop-$HADOOP_VERSION/etc/hadoop /etc/hadoop \
    && rm -rf /opt/hadoop/share/doc

# 로컬의 core-site.xml 파일을 복제
ADD core-site.xml /etc/hadoop/

# 실행 환경에 필요한 환경 변수 등록
ENV HADOOP_PREFIX /opt/hadoop
ENV HADOOP_CONF_DIR /etc/hadoop
ENV PATH $HADOOP_PREFIX/bin/:$PATH
ENV JAVA_HOME /usr/lib/jvm/zulu-8-amd64

기반 이미지인 azul/zulu-openjdk:8는 ubuntu 18 기반이라서 이미지 크기가 315MB로 꽤 크다.
이 크기를 작게 줄이려고 alpine 기반으로 생성해서는 안된다. Hadoop은 일반적인 GNU/Linux 환경에서 동작할 수 있도록 개발되었기 때문이다.

base/core-site.xml은 다음과 같이 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://namenode:9000/</value>
    <description>NameNode URI
    </description>
  </property>  
</configuration>

fs.defaultFS 설정은 NameNode 위치를 찾는 중요한 설정으로, DataNode 뿐만 아니라 각종 애플리케이션에서 NameNode에 파일 읽기/쓰기 요청을 할 때 사용되는 항목이다.
URI의 호스트 이름이 namenode로 설정되었는데, NameNode 컨테이너의 호스트 이름을 namenode로 지정할 것이다.

이제 터미널에서 base 디렉토리로 이동해서 baes 이미지를 생성해보자.

cd base
docker build -t hadoop-base:2.9.2 .

현재 위치한 폴더의 Dockerfile을 사용해서 docker 이미지를 빌드하겠다는 명령어이다. Dockerfile을 작성한대로 각 라인이 하나의 빌드 단계가 되어 명렁어를 실행하는 로그가 출력된다.

빌드가 완료되면 다음 명렁어로 로컬에 생성된 이미지를 확인할 수 있다.

docker images

REPOSITORY        TAG                 IMAGE ID            CREATED             SIZE
hadoop-base       2.9.2               fab79eab7d71        2 mins ago          1.2GB

이 이미지는 다음과 같은 이미지 계층 구조를 갖는다. 간단한 구조를 갖지만 이 base 이미지를 통해 모든 Hadoop 컴포넌트의 기반으로 사용할 수 있다.

Hadoop base 이미지 계층그림 1. Hadoop base 이미지 계층 구조. OS → Runtime → App base의 간단한 구조이다.

NameNode

Java와 Hadoop binary를 가지고 있는 base 이미지를 생성했으니, 이제 NameNode 이미지를 생성해보자.
NameNode 구성시 고려해야할 부분은 다음과 같다.

  • FsImage, EditLog를 저장하는 로컬 파일 시스템 경로
  • NameNode용 hdfs-site.xml 설정
  • NameNode 최초 구동 확인 및 네임스페이스 포맷

먼저 hdfs-site.xml 파일을 다음과 같이 작성한다.
dfs.namenode.name.dir은 FsImage, EditLog 파일을 저장하는 경로이다. HDFS 파일 블록 크기를 결정하는 dfs.blocksize 항목은 바이트 수로 여기서는 테스트를 위해 기본 값보다 훨씬 작은 10MB로 설정했다. (기본값은 128MB) 이 외의 항목들은 hdfs-default.xml 파일을 참고한다.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
  <property>
    <name>dfs.namenode.name.dir</name>
    <value>file:///opt/hadoop/dfs/name</value>
  </property>
  <property>
    <name>dfs.blocksize</name>
    <value>10485760</value>
  </property>
  <property>
    <name>dfs.client.use.datanode.hostname</name>
    <value>true</value>
  </property>
  <property>
    <name>dfs.namenode.rpc-bind-host</name>
    <value>0.0.0.0</value>
  </property>
  <property>
    <name>dfs.namenode.servicerpc-bind-host</name>
    <value>0.0.0.0</value>
  </property>
  <property>
    <name>dfs.namenode.http-bind-host</name>
    <value>0.0.0.0</value>
  </property>
  <property>
    <name>dfs.namenode.https-bind-host</name>
    <value>0.0.0.0</value>
  </property>
</configuration>

시작 스크립트인 start.sh에서는 NameNode의 네임스페이스가 포맷되었는지 확인하고, 포맷되기 전이라면 구동 전 포맷을 먼저 진행해야 한다.
다음과 같이 작성했다.

#!/bin/bash

# 네임스페이스 디렉토리를 입력받아서 
NAME_DIR=$1
echo $NAME_DIR

# 비어있지 않다면 이미 포맷된 것이므로 건너뛰고
if [ "$(ls -A $NAME_DIR)" ]; then
  echo "NameNode is already formatted."
# 비어있다면 포맷을 진행
else
  echo "Format NameNode."
  $HADOOP_PREFIX/bin/hdfs --config $HADOOP_CONF_DIR namenode -format
fi

# NameNode 기동
$HADOOP_PREFIX/bin/hdfs --config $HADOOP_CONF_DIR namenode

Dockerfile은 base 이미지 덕분에 간단하다.

# 방금 전 로컬에 생성한 base 이미지
FROM hadoop-base:2.9.2

# NameNode Web UI 응답 여부를 통해 Healthcheck
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD curl -f http://localhost:50070/ || exit 1

# 설정 파일 복제
ADD hdfs-site.xml /etc/hadoop/

# FsImage, EditLog 파일 경로를 volume으로 연결
RUN mkdir /opt/hadoop/dfs/name
VOLUME /opt/hadoop/dfs/name

# 실행 스크립트 복제
ADD start.sh /start.sh
RUN chmod a+x /start.sh

# NameNode의 HTTP, IPC 포트 노출
EXPOSE 50070 9000

# 시작 명령어 등록
CMD ["/start.sh", "/opt/hadoop/dfs/name"]

이제 이미지를 생성하자. 기본 명령어와 바이너리 파일을 다운로드 받는 등 시간이 오래 걸리는 작업은 이미 base 이미지에서 처리했기 때문에, 그 위에 다시 한번 계층을 쌓는 NameNode는 빌드 시간이 얼마 걸리지 않는 것을 볼 수 있다.

cd namenode
docker build -t hadoop-namenode:2.9.2 .

두 개의 이미지가 생성되었고 계층 구조에 하나의 이미지가 더해졌다.

Hadoop namenode 이미지 계층

NameNode 이미지를 생성했으니 이제 실제로 기동시켜볼 차례이다. 어차피 DataNode 이미지를 생성하면 docker compose를 구성하는 것이 훨씬 간편하므로 바로 compose 설정 파일을 구성하겠다.

먼저 root 디렉토리에 docker-compose.yml 파일을 생성한다. 디렉토리 구조를 보면 아래와 같다.

.
└── hadoop
    ├── base
    ├── namenode
    ├── datanode
    └── docker-compose.yml

설정 파일의 내용을 작성한다. services에는 기동할 컨테이너 정보를, volumes에는 마운트할 volume 정보를, networks에는 컨테이너 간 어떤 네트워크 구성을 사용할지 지정하는 항목이다.
volumes 이하에 정의된 각 항목은 다음과 같은 의미를 갖고 있다.

  • namenode:/opt/hadoop/dfs/namenamenode volume을 컨테이너의 /opt/hadoop/dfs/name 경로에 마운트
  • /tmp:/tmp: 컨테이너가 기동되는 호스트의 /tmp 경로를 컨테이너의 /tmp 경로로 마운트. 호스트와 컨테이너 간 파일을 쉽게 공유하기 위해서 지정함

콜론으로 구분된 설정 값의 뒷 부분이 컨테이너에 해당한다는 것을 기억하면 쉽게 이해할 수 있다.

version: "3"

services:
  namenode:
    image: hadoop-namenode:2.9.2
    container_name: namenode
    hostname: namenode
    ports:
      - "50070:50070"
      - "9000:9000"
    volumes:
      - namenode:/opt/hadoop/dfs/name
      - /tmp:/tmp
    networks:
      - bridge

volumes:
  namenode:

networks:
  bridge:

이제 이 설정 파일을 바탕으로 NameNode 컨테이너를 기동할 수 있다.

# docker-compose.yml 파일이 위치한 경로로 이동
cd hadoop

# 컨테이너를 백그라운드에서 실행
#  종료할 때에는 docker-compose down
docker-compose up -d
Creating namenode        ... done

# 기동중인 컨테이너 프로세스 확인
docker ps
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS                            PORTS               622e4f642435
hadoop-namenode:2.9.2          "/start.sh /opt/hado…"   10 seconds ago      Up 6 seconds (health: starting)   0.0.0.0.:9000->9000/tcp, 0.0.0.0.:50070->50070/tcp 

# 생성된 bridge 네트워크 확인
docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
0d9989bd9f78        bridge              bridge              local
9ae1ae84360f        hadoop_bridge       bridge              local
62a94ebd58b7        host                host                local

# 생성된 volume 확인
docker volume ls
DRIVER              VOLUME NAME
local               hadoop_namenode

# namenode 컨테이너의 로그 확인
docker logs -f namenode

docker compose로 기동한 후 마지막 명령어로 로그를 살펴보면, 네임스페이스를 포맷한 로그와 NameNode를 기동한 로그를 확인할 수 있다.
브라우저에서 http://localhost:50070 으로 접속하면 아래와 같은 NameNode Web UI에 접근한다.

NameNode Web UI

또한 NameNode가 기동되었으니, 아직 DataNode를 띄우지 않더라도 폴더의 생성과 삭제, 그리고 파일 목록 조회가 가능하다.
NameNode 컨테이너 내부에 있는 Hadoop 클라이언트를 실행해서 테스트해보자.

# namenode 이름의 컨테이너의 hadoop 클라이언트를 실행. 파일 시스템의 root 디렉토리를 모두 조회한다.
docker exec namenode /opt/hadoop/bin/hadoop fs -ls -R /

# 명령어 등록
alias hadoop="docker exec namenode /opt/hadoop/bin/hadoop"

# 폴더 생성/조회/삭제
hadoop fs -mkdir -p /tmp/test/app
hadoop fs -ls -R /tmp
hadoop fs -rm -r /tmp/test/app

docker exec [컨테이너 이름] [명령어]를 입력하면 동작 중인 컨테이너 내에서 [명령어]에 해당하는 명령어를 실행한 결과의 표준 출력을 현재 쉘에 출력한다.
컨테이너 내 자주 실행하는 프로그램응 alias로 등록해두면 편리하다. 여기에서는 NameNode의 bin/hadoop 프로그램을 hadoop으로 alias 지정했다.

DataNode

먼저 작성했던 JVM과 하둡 바이너리를 포함하는 base 이미지로부터 DataNode 이미지를 생성해보자. 고려해야할 부분은 두 가지이다.

  • 파일 블록을 저장하는 로컬 파일 시스템 경로
  • DataNode용 hdfs-site.xml 설정
    파일 블록 저장 경로는 $HADOOP_PREFIX/dfs/data로 설정할 것이다. 이 내용은 hdfs-site.xml 파일을 datanode 디렉토리 이하에 생성하고 내용을 다음과 같이 작성한다.
<configuration>
  <property>
    <name>dfs.datanode.data.dir</name>
    <value>file:///opt/hadoop/dfs/data</value>
  </property>
  <property>
    <name>dfs.blocksize</name>
    <value>10485760</value>
  </property>  
  <property>
    <name>dfs.datanode.use.datanode.hostname</name>
    <value>true</value>
  </property>
</configuration>

시작 스크립트는 start.sh에 다음과 같이 작성한다.

#!/bin/sh

$HADOOP_PREFIX/bin/hdfs --config $HADOOP_CONF_DIR datanode

hdfs 프로그램을 datanode 옵션으로 시작하면 DataNode 프로세스가 기동한다.

마지막으로 Dockerfile 이다. HEALTHCHECK에 Web UI 주소가 입력된 것과 EXPOSE에 명시한 포트를 눈여겨 본다.

FROM hadoop-base:2.9.2

# DataNode Web UI 응답 여부를 통해 Healthcheck
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3  CMD curl -f http://localhost:50075/ || exit 1

RUN mkdir /opt/hadoop/dfs/data
VOLUME /opt/hadoop/dfs/data

ADD start.sh /start.sh
RUN chmod a+x /start.sh

# WebUI, 데이터전송
EXPOSE 50075 50010

CMD ["/start.sh"]

NameNode 이미지를 구성할 때와 크게 다르지 않다. 이제 생성한 파일들을 가지고 이미지를 생성한다.

cd datanode
docker build -t hadoop-datanode:2.9.2 .

이제 컨테이너 실행 환경 정보를 담고 있는 docker-compose.yml 파일에 DataNode를 추가한다. 로컬 환경이지만 세 개의 DataNode를 띄울 것이다.

version: "3.4"

# 이미지와 네트워크 정보에 대한 base service를 지정
x-datanode_base: &datanode_base
  image: hadoop-datanode:2.9.2
  networks:
    - bridge

services:
  namenode:
    image: hadoop-namenode:2.9.2
    container_name: namenode
    hostname: namenode
    ports:
      - 50070:50070
      - 9000:9000
    volumes:
      - namenode:/opt/hadoop/dfs/name
      - /tmp:/tmp
    networks:
      - bridge

  datanode01:
    <<: *datanode_base
    container_name: datanode01
    hostname: datanode01
    volumes:
      - datanode01:/opt/hadoop/dfs/data
  
  datanode02:
    <<: *datanode_base
    container_name: datanode02
    hostname: datanode02
    volumes:
      - datanode02:/opt/hadoop/dfs/data

  datanode03:
    <<: *datanode_base
    container_name: datanode03
    hostname: datanode03
    volumes:
      - datanode03:/opt/hadoop/dfs/data

volumes:
  namenode:
  datanode01:
  datanode02:
  datanode03:

networks:
  bridge:

파일을 수정하고 docker-compose up -d를 다시 실행하면 세 개의 DataNode 컨테이너를 추가로 띄우게 된다. DataNode는 NameNode로 heartbeat을 보내면서 NameNode에 등록된다.

Configuring Kubernetes High Availability Clusters

소개

쿠버네티스는 마스터 노드에 내부적으로 API-SERVER를 가지고 있어 마스터 노드를 통해 워커 노드로 통신이 전달됩니다. 대량에 통신량이 발생하게 되면 마스터 노드는 부하를 많이 받아 장애 발생 가능성이 커지게 됩니다. 마스터 노드를 고가용성 클러스터로 연결하게 되면 통신량을 분산시킬 수 있고, 일부가 마스터 노드에서 장애가 발생시 워커 노드의 운영 시스템에는 영향을 줄일 수 있습니다.

구성 환경

아래 사양으로 총 3대 서버를 준비합니다.

OS: CentOS 7
CPU: 2
RAM: 4
Storage: 100G

구성목표

  1. 마스터 노드 3개를 클러스터구성
  2. 가상 네트워크(weave) 적용
  3. ceph storage 적용

도커&쿠버네티스 설치

CentOS 패키지 업데이트와 방화벽을 정지 및 스왑을 종료합니다.

$ sudo yum update -y
$ sudo systemctl disable firewalld && sudo systemctl stop firewalld
$ sudo selinux disabled
$ sudo setenforce 0
$ sudo iptables piv4 forward
$ sudosudo bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'
$ sudo swapoff -a
$ sudo sed -i '/swap/d' /etc/fstab

운영 환경에서는 아래 포트를 오픈하여 진행합니다.

노드 포트 TCP/UDP
마스터 6443, 2379-2380, 10250, 10251, 10252 TCP
마스터, 워커 6783 TCP
마스터, 워커 6783, 6784 UDP
워커 10250, 30000-32767 TCP
로드 밸런서 26443 TCP

호스트네임 설정

호스트네임은 서로 다르게 지정해야합니다.

$ sudo hostnamectl set-hostname node1

$ sudo hostnamectl set-hostname node2

$ sudo hostnamectl set-hostname node3

도커 설치

도커 레파지토리를 등록하여 yum 으로 설치 합니다.

$ sudo yum install -y yum-utils \
    device-mapper-persistent-data \
    lvm2

$ sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

$ sudo yum install docker-ce docker-ce-cli containerd.io

$ sudo systemctl start docker

설치 후 daemon.json을 추가하여 cgroupdriver를 systemd 옵션으로 사용할 수 있도록 합니다.

$ sudo cat <<EOF > /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
EOF

$ sudo systemctl daemon-reload
$ sudo systemctl enable docker
$ sudo systemctl restart docker

쿠버네티스 설치

쿠버네티스의 레파지토리 저장소를 등록하여 yum 으로 kubelet, kubeadm, kubectl을 설치합니다.

  • kubeadm: 클러스터 관련 작업시 사용됩니다.
  • kubectl: 클러스터의 서비스 및 pod 관리시 사용됩니다.
  • kubelet: 클러스터 에이전트역할을 합니다.
$ sudo cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg [https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg](https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg)
EOF

$ sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

$ sudo systemctl enable kubelet
$ sudo systemctl restart kubelet

node1, node2, node3에 도커와 쿠버네티스가 설치를 하였다면 아래 명령어를 통해 확인해볼 수 있습니다.

$ sudo docker verison
$ kubectl version

로드밸런서 설치

공식문서에서 사용되고 있는 HAProxy를 사용하도록 하겠습니다.
테스트환경이기 때문에 keepalive및 failover 기능없이 진행하도록 하겠습니다.

노드1에만 haproxy 를 설치하도록 하겠습니다.

$ sudo yum install haproxy -y

haproxy 로드밸런싱 설정

node1 IP의 26443포트로 전달받은 데이터를 node1 ~ node3의 6443 포트로 포워드 시켜줍니다.
라운드로빈으로 순차적으로 접근하도록 하겠습니다.

$ sudo cat <<EOF >> /etc/haproxy/haproxy.cfg
frontend kubernetes-master-lb
bind 0.0.0.0:26443
option tcplog
mode tcp
default_backend kubernetes-master-nodes

backend kubernetes-master-nodes
mode tcp
balance roundrobin
option tcp-check
option tcplog
server node1 <node1 IP>:6443 check
server node2 <node2 IP>:6443 check
server node3 <node3 IP>:6443 check
EOF

$ sudo systemctl restart haproxy

haproxy 확인

해당 포트가 오픈되어 있는지 확인합니다.
포트가 오픈되어 있어도 접근이 안될때는 방화벽을 확인해야 합니다.

netstat -an|grep 26443

클러스터 생성

클러스터 생성할때 –upload-certs, –control-plane-endpoint 플래그를 추가해야 인증서가 자동 배포되고, 마스터 노드 조인 명령어가 출력됩니다.

$ sudo kubeadm init --control-plane-endpoint "<노드1 DNS/IP or LoadBalancer DNS/IP>:26443" \
                --upload-certs \
                --pod-network-cidr "10.244.0.0/16"

config 생성

kubectl 사용하기 위해서는 사용자 디렉토리 하위에 .kube/config 가 필요합니다. kubeadm init 명령어를 진행하고 마지막에 로그를 잘보면 config를 생성하는 명령어가 적혀있습니다.

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

클러스터 연결

노드1에서 클러스터 생성시 kubeadm join 명령어가 출력되는데 –control-plane –certificate-key 플래그 포함하여 명령어를 실행하면 마스터 노드로 연결이 되고, 플래그는 추가하지 않고 사용하게 되면 워커노드로 연결됩니다.

노드2 클러스터 연결

$ sudo kubeadm join 192.168.248.251:26443 --token 06glbc.s0yaqonyajs95ez3 \
    --discovery-token-ca-cert-hash sha256:379ff0daa2cffa3f6581ae25c96aa3d6e4a9af43df92b8d0ac5a4dbb4c7e5547 \
    --control-plane --certificate-key 8eb7fa9a38ca1579c3fb61e0a1106935c4e9dfd81cbad259121f223f0adf555f

config 생성

노드2의 사용자에서도 kubectl 명령어를 사용하기 위해선 config를 생성해야 합니다.

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

노드3 클러스터 연결

노드3에서도 노드2와 동일하게 연결을 진행합니다.

$ sudo kubeadm join 192.168.248.251:26443 --token 06glbc.s0yaqonyajs95ez3 \
    --discovery-token-ca-cert-hash sha256:379ff0daa2cffa3f6581ae25c96aa3d6e4a9af43df92b8d0ac5a4dbb4c7e5547 \
    --control-plane --certificate-key 8eb7fa9a38ca1579c3fb61e0a1106935c4e9dfd81cbad259121f223f0adf555f

config 생성

노드3에서도 동일하게 config를 생성해야합니다.

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

클러스터 구성 확인

노드가 연결이 되었다면 아래 명령어를 실행시 노드가 전부 보여야합니다.

$ kubectl get node

마스터 노드에는 기본설정으로 pod 배포가 안됩니다. taint명령어를 통해 pod 배포가 가능하도록 하겠습니다.

$ kubectl taint nodes --all node-role.kubernetes.io/master-

가상 네트워크(weave) 적용

Calico, Canal, Clilum, Flannel, weave 등 다양한 가상네트워크가 있지만 공식문서에서 제공하는 weave를 적용하도록 하겠습니다.

$ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"

가상네트워크 적용 확인

최초 클러스터를 진행하게 되면 노드의 상태는 NotReady 입니다. 가상네트워크를 적용하게 되면 약 1 ~ 3분 소요되고 Ready 상태로 변경되게 됩니다. 이것으로 가상네트워크 적용이 완료 되었습니다.

$ kubectl get node

nginx 배포 해보기

nginx pod 3개를 배포하는 명령어입니다.

kubectl run --image=nginx --port 80 --replicas=3 nginx-app

아래 명령어를 통해 nginx-app 배포된 노드를 보면 node1 ~ 3 골고루 배포되어 있는걸 확인할 수 있습니다.

kubectl get pod -o wide

정리

이번에 쿠버네티스 고가용성 클러스터를 서버에 구축해보았습니다. 쿠버네티스 버전 1.6 이후 부터는 인증서배포 자동화, 클러스터 연결하는 방법이 간편하게 변경되었습니다. 이전 버전에서는 클러스터 구성하기위해선 복잡한 과정과 설정파일을 만들어야 했지만 이제는 간단하게 명령어 한줄만 입력하면 클러스터에 연결/해지를 하도록 변경되었습니다. 자유로운 노드 할당은 자원 낭비없이 효율적으로 관리하는데 장점이 될 것으로 보여집니다.

참고문서

Get alarms to Telegram in Grafana

1. 알람 채널 추가

  • Alerting > Notification channels 메뉴를 선택합니다.

    /images/2021-01-26-Common-Grafana-Alert/alert_01.png

  • New channel 을 클릭합니다. /images/2021-01-26-Common-Grafana-Alert/alert_02.png
  • Type 을 Telegram 으로 선택합니다.

    /images/2021-01-26-Common-Grafana-Alert/alert_03.png

    /images/2021-01-26-Common-Grafana-Alert/alert_04.png

    • Name, Default : 모든 알람 받기
    • Include image : 이미지 포함 여부
    • Disable Resolve Message : 해결 알람 받지 않기
    • Send reminders : 알림 상기시키기
    • Telegram API settings (BOT API Token, Chat ID) : 텔레그램에 봇을 추가하여 해당 토큰과 사용자의 챗 ID를 기입

    설정하고 Save 버튼을 눌러서 저장합니다.

  • 추가된 Channel 입니다. /images/2021-01-26-Common-Grafana-Alert/alert_05.png

2. 대시보드 패널에 알람 추가

  • 초당 요청량과 평균 응답속도 패널에 특정 수치로 알람을 설정 해보겠습니다. /images/2021-01-26-Common-Grafana-Alert/alert_06.png
  • 추가 하고싶은 패널의 수정 버튼을 누릅니다. 하단의 Alert 설정에서 Create Alert 버튼을 누릅니다. /images/2021-01-26-Common-Grafana-Alert/alert_07.png
  • 그래프 오른쪽 하트를 위 아래로 드래그하여 알람수치를 조정 할 수 있습니다. /images/2021-01-26-Common-Grafana-Alert/alert_08.png
  • 알람 이름과 규칙을 정합니다.

    Evaluate every 10s For 30s

    30초 동안 10초 마다 체크

  • Conditions은 여러개를 추가 할 수 있습니다.

    WHEN avg () OF query (A, 10s, now) IS ABOVE 400

    패널에 추가된 쿼리 A 수치가 10초 전부터 현재까지 평균 값이 400을 넘는 상태 /images/2021-01-26-Common-Grafana-Alert/alert_09.png

  • 평균 응답속도에 대해서도 알람을 설정하겠습니다.

    Evaluate every 10s For 0

    10초 마다 체크 하도록 설정했습니다.

    WHEN max () OF query (B, 10s, now) IS ABOVE 0.03

    OR max () OF query (C, 10s, now) IS ABOVE 0.03

    쿼리 B, C 중에서 10초 전부터 현재까지 최대값이 0.03초를 넘는 상태에 대해서 알람 설정을 했습니다. /images/2021-01-26-Common-Grafana-Alert/alert_10.png

    Conditions 에는 다양한 값으로 조건을 설정 할 수 있습니다. /images/2021-01-26-Common-Grafana-Alert/alert_10_1.png

3. 알람 확인 및 활용

  • 알림 리스트를 대시보드에 패널로 추가할 수 있습니다. /images/2021-01-26-Common-Grafana-Alert/alert_11.png
  • 대시보드에 알람 및 리스트가 추가된 모습입니다. /images/2021-01-26-Common-Grafana-Alert/alert_13.png
  • Telegram 알람 확인 앞서 Notification Channel 에서 Include image 를 설정하였기 때문에 이미지와 함께 알람이 오게 됩니다.

    초당 요청량은 ‘Evaluate every 10s For 30s’ 30초 동안 10초 마다 확인 하도록 설정 하였기 때문에 PENDING(보류중) 알람이 오지않고 보류 상태가 됩니다.

    평균 응답 속도에는 ‘Evaluate every 10s For 0’ 10초 마다 상태를 확인해서 보내도록 설정하여 보류하지 않고 바로 알람이 오게 됩니다.

    • 초록색 : OK
    • 주황색 : PENDING
    • 빨간색 : ALERTING

    /images/2021-01-26-Common-Grafana-Alert/alert_14.png

  • 알람 설정에서 State history 버튼을 눌러서 상태 히스토리를 확인 할 수 있습니다. /images/2021-01-26-Common-Grafana-Alert/alert_15.png
  • Alerting 메뉴에서 Alert Rules 을 선택하면 알람 설정 수정으로 바로가거나 시작 및 일시중지 제어 할 수 있습니다. /images/2021-01-26-Common-Grafana-Alert/alert_16.png

 

참고 자료

  • https://grafana.com/docs/grafana/latest/alerting/

Configuring Monitoring Dashboards Through Grafana

그라파나?

  • 그라파나는 데이터를 시각화하여 분석 및 모니터링을 용이하게 해주는 오픈소스 분석 플랫폼입니다. 여러 데이터 소스를 연동하여 사용 할 수 있으며 시각화 된 데이터들을 대시보드로 만들 수 있습니다.

    LIVE DEMO

  • 앞서 설치한 그라파나와 프로메테우스의 메트릭 정보를 조회하여 시각화 하는 방법에 대해 알아보겠습니다.

구성 방법

1. 데이터 소스 생성

  • Create a data source 메뉴를 선택합니다. /images/2020-03-17-Common-Dashborad/grafana_1.PNG
  • 데이터 소스로 프로메테우스를 선택합니다. /images/2020-03-17-Common-Dashborad/grafana_2.PNG
  • 프로메테우스 서버 정보를 입력한 후 하단의 Save&Test를 클릭합니다.
    • 연결테스트 후 이상이 없다면 저장됩니다.

/images/2020-03-17-Common-Dashborad/grafana_3.PNG

2. 대시 보드 생성

  • 홈으로 돌아와 Build a dashboard 메뉴를 선택합니다.

/images/2020-03-17-Common-Dashborad/grafana_4.PNG

  • 패널 선택장이 나옵니다. 대시보드는 이 패널들을 구성하고 배치하면 됩니다.
    • 메트릭 조회를 위해 Add Query를 선택합니다

/images/2020-03-17-Common-Dashborad/grafana_5PNG

  • Query 선택창에서 앞에 생성한 Data Source를 불러옵니다.
  • Metric에선 노드익스포터에서 수집한 항목을 선택합니다.

/images/2020-03-17-Common-Dashborad/grafana_7PNG

잠시 돌아와서 위에 선택한 메트릭 항목은 아래와 같은 구조를 가지고 있습니다.
따라서 Metric name으로만 조회시 프로메테우스 서버가 수집한 같은 이름 항목 전부를 조회 합니다. Label name으로 구분하여 조회 할 수 있습니다.
  • Prometheus Metric

/images/2020-03-17-Common-Dashborad/metrics.PNG

  • 이처럼 프로메테우스 서버에서도 메트릭을 조회할 수 있습니다.
  • node_cpu_seconds_total{job=”kube2”,mode=”system”}
    • ex) kube2 host에서 system 영역 cpu 사용률

/images/2020-03-17-Common-Dashborad/grafana_9.PNG

  • 다시 돌아와서 생성한 패널 쿼리에 적용해보겠습니다.

/images/2020-03-17-Common-Dashborad/grafana_10.PNG

  • node_cpu_seconds_total는 계속 누적이 되고 있는 값이기 때문에 rate함수를 사용합니다.
  • rate(node_cpu_seconds_total{job=”kube2”,mode=”system”}[10m])
    • 10분동안 CPU 사용율 변화수치를 초당으로 변환

/images/2020-03-17-Common-Dashborad/grafana_11.PNG

  • CPU 코어의 평균을 구하여 해당 서버의 CPU 평균 사용률을 표시합니다. -avg(rate(node_cpu_seconds_total{job=”kube2”,mode=”system”}[10m])) by (job)

/images/2020-03-17-Common-Dashborad/grafana_12.PNG

  • 설정에서 그래프 종류를 선택할 수 있습니다.

/images/2020-03-17-Common-Dashborad/grafana_6.PNG

이처럼 자신의 필요한 메트릭 정보를 집계하여 패널로 만든 후 대시보드를 구성하면 됩니다.

외부 대시보드 포맷 사용

  • 매트릭 정보를 직접 집계하여 사용하거나 필요한 데이터를 정의하는게 나름 번거로운 작업이라 그라파나 홈페이지에 다른 여러 사용자들이 구성해놓은 대시보드 포맷을 사용하면 더 쉽게 대시보드를구현할 수 있습니다.

https://grafana.com/grafana/dashboards

/images/2020-03-17-Common-Dashborad/grafana_13.PNG

  • import 화면에서 다운받은 JSON 파일을 upload하거나 COPY ID를 입력하여 적용합니다.

/images/2020-03-17-Common-Dashborad/grafana_14.PNG

결론

프로메테우스, 그라파나를 통해 비교적 쉽게 모니터링을 위한 프로세스들을 만들 수 있었습니다. 여러 익스포터를 통해 필요한 매트릭 수집을 확장할 수 있다는게 큰 장점인 것 같으며 PULL 방식이라 부하에 따른 장애나 성능감소를 걱정하지 않아도 된다고 합니다. 그라나파를 통해 매트릭 데이터를 보기 쉽게 만들 수 있었으며 다양한 데이터 소스를 지원하는 만큼 여러 분야에서 활용하면 좋을 것 같습니다.

Installing Prometheus and Grafana Using Docker-Compose

프로메테우스?

  • 프로메테우스는 오픈소스기반의 모니터링 솔루션이며 모니터링 대상이 되는 metric 정보를 pull 방식으로 수집합니다. 공식적으로 제공하는 exporter뿐만 아니라 여러 Third-pary exporter를 통하여 다양한 플랫폼을 모니터링 할 수 있는 장점이 있습니다.

/images/2020-03-16-Common-Prometheus/architecture.PNG

  • 여기서는 도커 컴포즈를 통하여 프로메테우스와 그라파나를 설치하고 Node-Exporter를 통해 받아온 Metric 정보로 그라파나 대시보드를 구성해보겠습니다.

설치 및 구성

1. 구성 환경

CENTOS 7.8

DOCKER 19.03.5, build 633a0ea

DOCKER-COMPOSE 1.25.3, build d4d1b42b

2. docker-compose.yml 작성

  • 공식적으로 설정된 포트들이 이미 사용중임에 따라 다른 포트로 대체하였습니다.
version: '3.7'
services:

  # 직접 설치로 대체
  #node:
  #  image: prom/node-exporter
  #  container_name: node-exporter
  #  ports:
  #    - 9101:9100
  #  networks:
  #    - prometheus-network

  prometheus:
    image: prom/prometheus:v2.16.0
    container_name: prometheus
    network_mode: "host" 
    command:
      - '--web.listen-address=0.0.0.0:9099'
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--storage.tsdb.retention.time=200h'
      - '--web.enable-lifecycle'
    volumes:
      - /data/prometheus:/etc/prometheus
      - /data/prometheus/data:/prometheus
    ports:
      - 9099:9099
    networks:
	  - prometheus-network

  grafana:
    container_name: grafana
    image: grafana/grafana:6.6.2
    environment:
      - GF_SECURITY_ADMIN_USER=user1
      - GF_SECURITY_ADMIN_PASSWORD=user1
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - /data/grafana/data:/var/lib/grafana
      - /data/grafana/provisioning:/etc/grafana/provisioning
    ports:
      - 9900:3000
    depends_on:
      - prometheus
    networks:
      - prometheus-network

networks:
  prometheus-network:

부가 설명

  • 도커에서 노드 익스포터를 실행하는 것은 권장하지 않는다고 합니다. 이유는 도커는 머신의 내부동작과 컨테이너를 격리시키려고 하기 때문에 노드 익스포터에서 내부 동작 결과가 잘동작하지 않을 수 있기 때문입니다.
- #node:
  #  image: prom/node-exporter
  #  container_name: node-exporter
  #  ports:
  #    - 9101:9100
  #  networks:
  #    - prometheus-network
  • 컨테이너에서 호스트에 떠있는 프로세스로 접근이 안되어 NETWORK MODE를 HOST로 설정하였습니다.
network_mode: "host" 
  • 기존 구성 환경에서는 이미 기본포트가 쓰이고 있기 때문에 별도 설정을 통해 포트를 변경하였으며 config 파일 경로를 지정하였습니다.
command:
      - '--web.listen-address=0.0.0.0:9099'
      - '--config.file=/etc/prometheus/prometheus.yml'
  • 컨테이너 종료시에 데이터가 삭제될 수 있으므로 HOST의 볼륨 경로를 지정하였습니다.
volumes:
      - /data/prometheus:/etc/prometheus
      - /data/prometheus/data:/prometheus

3. prometheus.config 작성

  • 환경설정 파일을 작성합니다
  • 매트릭 수집 주기 설정
# my global config
global:
  scrape_interval:     15s # 15초 주기로 매트릭 수집
  • 익스포터 설정
  • 추가 될 때 마다 해당 형식으로 설정 파일내에 추가합니다.
# Exporter 설정
  - job_name: 'kube1'    # 사용할 이름
    scrape_interval: 10s # 주기
    static_configs:      # 익스포트 프로세스 설정
    - targets: ['prom1.danawa.com:9110','prom1.danawa.com:9111']

prometheus.config

# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"


# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  - job_name: 'prometheus'

    static_configs:
    - targets: ['127.0.0.1:9099']

  # Exporter 설정
  - job_name: 'prom1'
    scrape_interval: 10s
    static_configs:
    - targets: ['prom1.danawa.com:9110','prom1.danawa.com:9111']

  - job_name: 'prom2'

    static_configs:
    - targets: ['prom2.danawa.com:9110']

  - job_name: 'prom3'

    static_configs:
    - targets: ['prom3.danawa.com:9110']

4. docker-compose 실행

docker-compose up -d

결과
Creating network "prometheus_prometheus-network" with the default driver
Creating node-exporter ... done
Creating prometheus    ... done
Creating grafana       ... done

5. node-exporter 설치

## 사용버전 0.18.1
## node-exporter의 기본 포트는 9100이지만 구성 환경에서 이미 사용중인 포트이므로 임의의 포트로 설정하여 기동하였습니다.

1. wget https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_exporter-0.18.1.linux-amd64.tar.gz

2. tar xvfz node_exporter-0.18.1.linux-amd64.tar.gz

3. mv node_exporter-0.18.1.linux-amd64/node_exporter /usr/local/bin/

4. /usr/local/bin/node_exporter --web.listen-address=:9110
  • 확인 : http://prom1.danawa.com:9110/metrics – 기본포트 9100

/images/2020-03-16-Common-Prometheus/node_exporter.PNG

6. prometheus 확인

http://prom1.danawa.com:9099 – 기본포트 9090

  • 익스포터로 수집된 메트릭정보를 조회해 볼 수 있습니다.
  • PROMQL을 사용해 데이터를 집계 할 수 있습니다.

/images/2020-03-16-Common-Prometheus/prometheus1.PNG

http://prom1.danawa.com:9099/targets

  • 익스포터의 상태를 확인 할 수 있습니다.

/images/2020-03-16-Common-Prometheus/prometheus1_2.PNG

6. grafana 확인

http://prom1.danawa.com:9900 – 기본포트 3000 /images/2020-03-16-Common-Prometheus/grafana.PNG

/images/2020-03-16-Common-Prometheus/grafana2.PNG

Ubuntu에 minikube설치하기

내가 가진 리눅스 환경에 쿠버네티스 실습 환경을 만들기 위해 minikube를 설치합니다.

 

이 포스트는 우분투 20.04 LTS버젼 기준으로 작성했습니다. 설치 전에 버전을 꼭 확인 해보세요.

미리 설치해야 하는 것 – Docker, VirtualBox (가상환경 내에 설치시에는 필요 없음)

Docker 설치

도커를 설치 해줍니다. Docker가 설치 되어 있다면 도커 설치는 넘어갑니다.

sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
sudo apt-get install docker-ce docker-ce-cli containerd.io

여기까지가 Docker설치 명령입니다. 단순히 docker-ce만 설치 한다고 되는 것은 아닙니다. 위 단계를 모두 거쳐야 합니다.

 

 

설치가 완료된 후 docker라고 입력 했을 때 위와 같이 나오면 잘 설치 된 것입니다.

버추얼 박스 설치

minikube를 설치 하려면 OS에 맞는 하이퍼바이저를 설치 해주어야 합니다. 저는 virtualbox를 설치 했습니다.

sudo apt-get install virtualbox

위 버추얼박스를 설치 해줍니다.

Minikube설치

아래 명령어로 minikube를 다운로드 받습니다.

curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 \
  && chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

아래 명령어로 minikube를 실행 합니다.

minikube start

 

 

위와 같이 나오면 잘 설치되고 실행된 것입니다.

minikube start –vm-driver=none   (가상환경 내에 구동시 필요)

저 처럼 amd를 사용해서 에러가 나시는 분들은 위 명령어로 실행을 해보시기 바랍니다.

 

 

위와같이 GUEST_MISSING_CONNTRACK 에러가 나는 경우

sudo apt-get install -y conntrack

위 명령어로 conntrack을 설치 하시고 실행 하시기 바랍니다.

Kubectl설치

쿠버네티스 api에 명령을 전송 하려면 kubectl을 이용해야 합니다.

apt-get을 이용해 kubectl을 설치 합니다.

sudo apt-get update && sudo apt-get install -y apt-transport-https gnupg2
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl

 

Nginx띄워보기

잘 설치되었으면 Nginx를 띄워보겠습니다.

kubectl run webserver –image=nginx:1.14 –port 80

 

 

kubectl get po

위 명령어를 이용해 webserver가 Running상태인지 확인 합니다.

 

end.

Redis를 Docker Compose 로 띄우기

01. docker image 다운로드

>> docker pull redis:alpine

위와 같이 pull 커맨드를 이용해서 redis:alpine 이미지를 다운로드 받습니다.

alpine 은 태그를 의미하며 redis의 버전 등의 값을 줄수 있습니다. (생략하면 latest 를 받음)

alpine 태그의 특징은 이미지를 경량화 시켜서 용량이 적습니다.

이미지 용량 차이를 확인해보니 아래와 같네요.

>> docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
redis        alpine    c678242f9116   5 weeks ago    31.6MB
redis        6.0.6     1319b1eaa0b7   5 months ago   104MB

 

 

 

02. docker로 실행

>> docker run --name redis_boot -d -p 6379:6379 reids:alpine

위와 같이 run 커맨드를 통해 docker container를 띄우면 됩니다.

  • name : container명을 지정합니다.
  • d, —detach : 백그라운드로 실행합니다.
  • p : host의 port와 container port 설정합니다.

그리고 마지막에 이미지명:태그명 해주면 됩니다.

 

근데 매번 저 명령어를 쳐주기 귀찮을겁니다.

docker-compose 를 사용하면 yml 파일로 컨테이너를 띄울 수 있습니다.

 

 

03. yml 파일 작성

# redis-server.yml
version: '3.7'
services:
    redis:
      image: redis:alpine
      command: redis-server --port 6379
      container_name: redis_boot
      hostname: redis_boot
      labels:
        - "name=redis"
        - "mode=standalone"
      ports:
        - 6379:6379

위와 같이 작성해줍니다.

yml 파일 작성할 때는 띄어쓰기 잘하셔야됩니다.

key: value 이런식으로…

 

 

04. docker-compose up (시작)

>> docker-compose -f ./redis_server.yml up -d

위와 같이 up 커맨드를 이용해서 띄울수 있습니다.

  • -d  옵션을 줘서 백그라운드 실행했구요.
  • -f 는 yml 파일 경로를 지정하여 해당 yml파일을 실행하도록 합니다.(default는 docker-compose.yml 이고, 이 경우 따로 지정할 필요가 없습니다.
>> docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                    NAMES
1b7d82a59165   redis:alpine   "docker-entrypoint.s…"   3 seconds ago   Up 2 seconds   0.0.0.0:6379->6379/tcp   redis_boot

잘 뜨네요.

 

 

05. redis-cli 사용

컨테이너에 접속하여

redis 커맨드 라인 명령어 도구인 redis-cli 를 이용해 봅시다.

>> docker exec -it redis_boot redis-cli
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> SET abc 123
OK
127.0.0.1:6379> GET abc
"123"
127.0.0.1:6379> 

exec 커맨드를 사용해 docker container 내부에 명령어를 실행 해볼수 있습니다.

  • 현재 터미널에서 상호작용하기 위해 -i, -t 옵션을 줬습니다.
  • 컨테이너명인 redis_boot 인자로 주고.
  • 마지막으로 redis-cli 커맨드를 줍니다.
  • redis 명령어 테스트 해보니 잘되네요.

 

 

06. docker-compose down (종료)

>> docker-compose -f ./redis_server.yml down 
Stopping redis_boot ... done
Removing redis_boot ... done
Removing network redis_server_default

종료는 down 커맨드를 사용하면 됩니다.

Docker build 로 Elasticsearch docker image 만들기

특정 이미지를 기반으로 하여 새로운 이미지를 만들 수 있는 Docker build에 대해 공부와 함께 이전에 ubuntu 14.04 위에 서비스로 elasticsearch 를 설치했던 내용들을 정리하기 위해 Dockerfile을 만듬.

해당 elasticsearch는 x-pack을 사용하여, 인증받지 않은 임의의 유저는 특정 클러스터에 read 만 할 수 있도록 함.

아래 Dockerfileelasticsearch.ymlroles.yml를 한 폴더에 놓은 뒤, $ docker build 실행.

FROM mcpayment/ubuntu1404-java8
MAINTAINER mail@jungbin.kim
# repository index 업데이트
RUN apt-get -y -qq update
RUN wget -qO – https://artifacts.elastic.co/GPG-KEY-elasticsearch | apt-key add –
# Installing from the APT repository
RUN apt-get -y -qq install apt-transport-https
RUN echo “deb https://artifacts.elastic.co/packages/5.x/apt stable main” | tee -a /etc/apt/sources.list.d/elastic-5.x.list
RUN apt-get -y -qq update && \
apt-get -y -qq install elasticsearch
# Install x-pack & Set super user(as admin)
WORKDIR /usr/share/elasticsearch
RUN bin/elasticsearch-plugin install x-pack –batch && \
bin/x-pack/users useradd admin_user -p testPassword -r superuser
# config 파일 소스
COPY elasticsearch.yml /etc/elasticsearch/
COPY roles.yml /etc/elasticsearch/x-pack/
# 나중에 내부 테스트를 위함
# curl 설치
RUN apt-get -y -qq install curl
# vi option 추가
RUN echo “set autoindent \nset number \nset bs=2 \nset nocp” >> ~/.exrc
# 도커 컨테이너가 실행되었을 때 요청을 기다리고 있는(Listen) 포트를 지정
EXPOSE 9200
# 도커 컨테이너가 실행되었을 때 실행되는 명령어를 정의
CMD service elasticsearch start && bash
view rawDockerfile hosted with ❤ by GitHub
# Set the bind address to a specific IP (IPv4 or IPv6):
# 192.168.1.10 과 같은 ip에 접근하기 위함
network.host: 0.0.0.0
# create an anoynomous user to allow interaction without auth
xpack.security.authc:
# 임의의 유저(유저 이름 anonymous)에 viewer라는 role을 줌.
# (x-pack/roles.yml에서 viewer는 read만 가능하게 설정)
# https://www.elastic.co/guide/en/elasticsearch/reference/5.6/security-settings.html#anonymous-access-settings
anonymous:
username: anonymous
roles: viewer
# Disable default user ‘elastic’
# https://www.elastic.co/guide/en/elasticsearch/reference/5.6/security-settings.html#password-security-settings
accept_default_password: false
view rawelasticsearch.yml hosted with ❤ by GitHub
# The default roles file is empty as the preferred method of defining roles is
# through the API/UI. File based roles are useful in error scenarios when the
# API based roles may not be available.
viewer:
run_as: [ ‘anonymous’ ] # 적용될 유저 이름 여기서는 인증 받지 않은 임의의 유저
cluster: [ “monitor” ] # 적용될 cluster들
indices:
names: [ ‘*’ ] # 허용 index를 패턴을 포함하여 정의 한다.
privileges: [ ‘read’ ] # 권한은 read만 부여한다.
query: {“match_all”: {}} # 권한으로 열어줄 문서 목록을 쿼리로 정의한다.
view rawroles.yml hosted with ❤ by GitHub

위와 같이 dockerfile을 별도로 만들지 않아도, Docker hub에 5.6 버전까지 docker 이미지가 있으며, 최신 버전(현재 6.3)의 elasticsearch docker image는 공식 제공 페이지에 존재.

사용한 docker file 명령어Permalink

  • RUN: 쉘 명령어를 수행
  • WORKDIR: 현재 가리키고 있는 폴더 위치 변경
  • COPY: 특정 파일이나 폴더 docker image에 복사
  • EXPOSE: docker container 내의 port
  • CMD: docker image를 container로 실행할 때 실행되는 명령어 지정

Error HandlingPermalink

apt-get install apt-transport-https 명령어를 실행할 때, Unable to locate package apt-transport-https 에러 발생Permalink

이 글을 참고하여, /etc/apt/sources.list.d/ 경로에 elastic 관련 .list 파일을 삭제하고, 다시 install 명령어 실행.