ETL 메커니즘을 Docker로 구현해 보았습니다.

14938 단어 ETL도커EmbulkRails
안녕하세요 ayalan입니다.

이전 세미나에서 데이터 분석 기반의 이야기를 들었을 때 규모가 너무 커서 잘 모르는 경우가 있었습니다.
CPU보다 GPU가 좋다든가, IoT의 데이터를 실시간으로 업로드한다든지 실제로 그런 일 좀 할 수 없고, 모르면 분위기 잡을 수 없는 사람이 대부분이라고 생각합니다.
그러나 좀 더 규모가 작은 데이터에서도 분석 사용하고 싶은, 분석하고 싶다는 사람도 많을까 생각합니다.
이번에 해본 것은 해석원의 데이터를 ETL 툴로 Google의 BigQuery에 데이터를 집약하는 구조를 Docker를 사용해 구현해 보았습니다.

운영 환경



호스트




품목
버전


os
OS X El Capitan 10.11.6

dokcer
17.09.0-ce

docker-compose
1.16.1

루비
2.3.5


docker가 작동하면 어떤 환경에서도 문제가 없습니다. 다만, dokcer와 docker-compose는 낡은 버젼이라고 동작하지 않을 가능성도 있으므로, 가능한 한 최신 버젼이 좋을까라고 생각합니다.

컨테이너



ETL + 작업 스케줄러 (ETL : Embulk, 작업 스케줄러 : kuroko2)




품목
버전


base image
alpine:3.6

openjdk
1.8.0_131

루비
2.3.5p376

jruby
jruby 9.1.14.0 (2.3.3)

bundler
1.16.0

rails
5.1.4

puma
5.1.4

kuroko2
0.4.3

Embulk
v0.8.38


ETL은 Embulk을 사용하고 있으며 작업 스케줄러는 쿡 패드의 쿠로코 2을 사용합니다.

데이터베이스




품목
버전


base image
mariadb:latest

mariadb
15.1 Distrib 10.2.11


실시간 모니터링(netdata)




품목
버전


base image
titpetric/netdata:latest

netdata
1.8.0-624-gf14f228_rolling


ETL+ 작업 스케줄러 컨테이너 작성



kuroko2의 초기 설정



쿡 패드의 쿠로코 2 을 사용하기 위해 Administrator Guide 을 참고로 초기 설정을 합니다.
Dockerfile내에서 rails new 그러면 이미지 사이즈가 비대화하므로, 이미지 밖에서 rails new 한 것을 docker의 이미지안에 짜넣습니다.
rails new my_kuroko2 --database=mysql --skip-turbolinks --skip-javascript -m https://raw.githubusercontent.com/cookpad/kuroko2/master/app_template.rb

Docker 이미지 만들기



본래는 1프로세스 1컨테이너가 이상입니다만, ETL툴의 Embulk는 커멘드 툴이며, 작업 스케줄러의 Kuroko2로 Rails Sever(puma)와 작업 실행하는 프로세스와 복수 가동시키지 않으면 안 되었기 때문에, 1컨테이너에 복수 기능을 갖게 하기로 했습니다.

Dockerfile
FROM ayaran/openjdk:8u131
MAINTAINER [email protected]

RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.5/main" >> /etc/apk/repositories
RUN echo "http://dl-cdn.alpinelinux.org/alpine/v3.5/community" >> /etc/apk/repositories
RUN apk update && apk add --no-cache \
  openrc \
  curl \
  cmake \
  mysql-dev \
  mysql-client \
  build-base \
  libxml2-dev \
  libxslt-dev \
  linux-headers \
  libffi-dev \
  openssl \
  nodejs \
  jruby \
  tzdata

RUN apk add --no-cache \
  ruby=2.3.6-r0 \
  ruby-dev=2.3.6-r0 \
  ruby-bigdecimal=2.3.6-r0 \
  ruby-rdoc=2.3.6-r0 \
  ruby-io-console=2.3.6-r0 \
  ruby-irb=2.3.6-r0

RUN gem install --no-doc bundler

RUN curl -L "https://dl.embulk.org/embulk-latest.jar" -o /usr/local/bin/embulk
RUN chmod +x /usr/local/bin/embulk

COPY ./Gemfile /opt/embulk/Gemfile

RUN gem install --no-doc bundler --install-dir /opt/embluk/bundle/ruby/2.3.0/gems
RUN embulk bundle install --gemfile /opt/embulk/Gemfile --path /opt/embulk/bundle

ADD ./my_kuroko2 /opt/kuroko2
WORKDIR /opt/kuroko2

RUN bundle install --gemfile /opt/kuroko2/Gemfile --path /opt/kuroko2/bundle
COPY ./config/database.yml /opt/kuroko2/config/database.yml
COPY ./config/application.rb /opt/kuroko2/config/application.rb

RUN mkdir -p /opt/kuroko2/tmp/pids

COPY ./scripts/db-migrate /etc/init.d/db-migrate
COPY ./scripts/puma /etc/init.d/puma
COPY ./scripts/command-executor /etc/init.d/command-executor
COPY ./scripts/job-scheduler /etc/init.d/job-scheduler
COPY ./scripts/workflow-processor /etc/init.d/workflow-processor

RUN rc-update add db-migrate default
RUN rc-update add puma default
RUN rc-update add command-executor default
RUN rc-update add job-scheduler default
RUN rc-update add workflow-processor default

RUN rc-status && touch /run/openrc/softlevel

RUN sed -i -- 's/^tty/#tty/g' /etc/inittab

각 프로세스를 데몬화하고 기동하고 싶었기 때문에 OpenRC의 기동 스크립트를 만들어 설치하고 있습니다.
특히, 어플리케이션 컨테이너를 기동할 때에 Database의 초기 기동이 완료하고 있는 것이 전제이므로, docker docs 를 참고로 Database의 최초 기동 완료를 확인하고 나서 db:migrate 가 움직이는 스크립트 작성하고 있습니다.

db-migrate
#!/sbin/openrc-run

prog=db-migrate
RAILS_ROOT=/opt/kuroko2
host=database
user=kuroko
password=kuroko
cmd="/usr/bin/bundle exec rails db:migrate"

start() {
    echo -n $"Starting $prog: "
    until mysql -h"$host" -u"$user" -p"$password" -e "show databases;"; do
        echo -n "MySQL is unavailable - sleeping"
        sleep 1
    done

    >&2 echo "MySQL is up - executing command"
    cd $RAILS_ROOT
    $cmd
    RETVAL=$?
    echo
    eend $?
}

만든 컨테이너들의 시작



docker-compose로 기동시키기 위해서, 아래 docker-compose.yml 를 준비.

docker-compose.yml
version: '3.2'

services:
  database:
    hostname: mariadb
    container_name: mariadb
    image: mariadb
    expose:
      - 3306
    environment:
      - MYSQL_RANDOM_ROOT_PASSWORD=yes
      - MYSQL_DATABASE=kuroko2_development
      - MYSQL_USER=kuroko
      - MYSQL_PASSWORD=kuroko
    restart: always

  kuroko2:
    hostname: kuroko2
    container_name: kuroko2
    image: ayaran/kuroko2
    expose:
      - 80
    ports:
      - 80:80
    links:
      - database:database
    depends_on:
      - "database"
    volumes:
      - ./.env:/opt/kuroko2/.env
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    command: /sbin/init
    restart: always

  netdata:
    hostname: netdata
    container_name: netdata
    image: titpetric/netdata
    expose:
      - 19999
    ports:
      - 19999:19999
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - "TZ=Japan"
    tty: true
    restart: always

Database를 영속화하는 경우는 호스트측의 volume를 마운트 해 두면 좋다.
  database:
    hostname: mariadb
    container_name: mariadb
    image: mariadb
    expose:
      - 3306
    environment:
      - MYSQL_RANDOM_ROOT_PASSWORD=yes
      - MYSQL_DATABASE=kuroko2_development
      - MYSQL_USER=kuroko
      - MYSQL_PASSWORD=kuroko
    volumes:
      - /path/to/mysql:/var/lib/mysql
    restart: always

부팅
docker-compose -f docker-compose.yml up -d
이제 시작합니다.
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
185609c9aba9        ayaran/kuroko2      "/sbin/init"             6 seconds ago       Up 4 seconds        0.0.0.0:80->80/tcp         kuroko2
5103d6d4b17f        mariadb             "docker-entrypoint..."   3 hours ago         Up 26 minutes       3306/tcp                   mariadb
4fc893ed9d35        titpetric/netdata   "/run.sh"                3 hours ago         Up 26 minutes       0.0.0.0:19999->19999/tcp   netdata
http://localhost/에 액세스하면 GoogleAuth 화면이 나오고,



인증하면 kuroko2 화면이 나타납니다.



여기에서 BigQuery로 데이터 전송할 JOB를 등록하여 실행합니다.

또한 http://localhost:19999에 액세스하면 리소스 모니터링 화면도 볼 수 있습니다.



요약



실제로 데이터를 전송하는 곳까지 걸리지 않았지만, 생각했던 것보다 쉽게 ​​구조를 만들 수있었습니다.
(컨테이너의 이미지만 있으면 약간의 config만 준비하면 명령 하나 두드리는 것만으로 움직이는 것이므로.)

좋은 웹페이지 즐겨찾기