웹사이트 검색

Confd 및 Etcd를 사용하여 CoreOS에서 서비스를 동적으로 재구성하는 방법


소개

CoreOS를 사용하면 컴퓨터 클러스터 전체에서 Docker 컨테이너의 서비스를 쉽게 실행할 수 있습니다. 이를 위한 절차에는 일반적으로 하나 이상의 서비스 인스턴스를 시작한 다음 각 인스턴스를 CoreOS의 분산 키-값 저장소인 etcd에 등록하는 작업이 포함됩니다.

이 패턴을 활용하여 관련 서비스는 인프라 상태에 대한 귀중한 정보를 얻고 이 지식을 사용하여 자체 동작을 알릴 수 있습니다. 이렇게 하면 중요한 etcd 값이 변경될 때마다 서비스가 동적으로 구성될 수 있습니다.

이 가이드에서는 분산된 키-값 저장소의 변경 사항을 감시하도록 특별히 제작된 confd라는 도구에 대해 설명합니다. Docker 컨테이너 내에서 실행되며 구성 수정 및 서비스 다시 로드를 트리거하는 데 사용됩니다.

전제 조건 및 목표

이 가이드를 진행하려면 CoreOS 및 해당 구성 요소 부분에 대한 기본적인 이해가 있어야 합니다. 이전 가이드에서는 CoreOS 클러스터를 설정하고 클러스터를 관리하는 데 사용되는 일부 도구에 익숙해졌습니다.

다음은 이 문서를 시작하기 전에 읽어야 할 가이드입니다. 이 가이드에 설명된 일부 서비스의 동작을 수정할 예정이므로 자료를 이해하는 것이 중요하지만 이 가이드를 사용할 때 처음부터 새로 시작해야 합니다.

  • DigitalOcean에서 CoreOS 클러스터를 설정하는 방법
  • CoreOS 클러스터에서 서비스를 만들고 실행하는 방법
  • 플릿 단위 파일을 사용하여 CoreOS 클러스터를 위한 유연한 서비스를 생성하는 방법

또한 사용하게 될 일부 관리 도구에 더 익숙해지려면 다음 가이드를 참조하십시오.

  • Fleet 및 Fleetctl을 사용하여 CoreOS 클러스터를 관리하는 방법
  • Etcdctl 및 Etcd, CoreOS의 분산 키-값 저장소 사용 방법

"유연한 서비스를 만드는 방법\ 가이드는 이 가이드에서 특히 중요합니다. 템플릿 기본 + 사이드킥 서비스가 이 가이드에서 설정할 프런트 엔드 서비스의 기초 역할을 하기 때문입니다. 위의 가이드는 Apache 및 사이드킥 서비스 생성에 대해 설명하지만 처음부터 쉽게 시작할 수 있도록 이 가이드에 대한 몇 가지 구성 변경 사항이 있습니다. 이 가이드에서는 이러한 서비스의 수정된 버전을 생성할 것입니다.

이 튜토리얼에서는 Nginx로 새 애플리케이션 컨테이너를 만드는 데 중점을 둘 것입니다. 이는 템플릿 파일에서 생성할 수 있는 다양한 Apache 인스턴스에 대한 리버스 프록시 역할을 합니다. Nginx 컨테이너는 사이드킥 서비스가 담당하는 서비스 등록을 감시하기 위해 confd로 구성됩니다.

이 시리즈를 통해 사용했던 것과 동일한 3개의 머신 클러스터로 시작합니다.

  • coreos-1
  • coreos-2
  • coreos-3

이전 가이드 읽기를 마치고 세 대의 머신 클러스터를 사용할 수 있게 되면 계속 진행합니다.

백엔드 Apache 서비스 구성

백엔드 Apache 서비스를 설정하는 것으로 시작하겠습니다. 이것은 주로 이전 가이드의 마지막 부분을 반영하지만 약간의 미묘한 차이로 인해 여기에서 전체 절차를 실행합니다.

시작하려면 CoreOS 시스템 중 하나에 로그인하십시오.

ssh -A core@ip_address

Apache 컨테이너 설정

기본 Apache 컨테이너를 만드는 것부터 시작하겠습니다. 이것은 실제로 마지막 가이드와 동일하므로 Docker Hub 계정에서 해당 이미지를 이미 사용할 수 있는 경우 이 작업을 다시 수행할 필요가 없습니다. 이 컨테이너는 Ubuntu 14.04 컨테이너 이미지를 기반으로 합니다.

다음을 입력하여 기본 이미지를 풀다운하고 컨테이너 인스턴스를 시작할 수 있습니다.

docker run -i -t ubuntu:14.04 /bin/bash

컨테이너가 시작되면 bash 세션으로 이동합니다. 여기에서 로컬 apt 패키지 인덱스를 업데이트하고 apache2를 설치합니다.

apt-get update
apt-get install apache2 -y

또한 기본 페이지를 설정합니다.

echo "<h1>Running from Docker on CoreOS</h1>" > /var/www/html/index.html

필요한 상태이므로 이제 컨테이너를 종료할 수 있습니다.

exit

다음을 입력하여 Docker Hub에 로그인하거나 계정을 만드십시오.

docker login

Docker Hub 계정에 대한 사용자 이름, 암호 및 이메일 주소를 제공해야 합니다.

다음으로 방금 떠난 인스턴스의 컨테이너 ID를 가져옵니다.

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
1db0c9a40c0d        ubuntu:14.04        "/bin/bash"         2 minutes ago       Exited (0) 4 seconds ago                       jolly_pare

위의 강조 표시된 필드는 컨테이너 ID입니다. 자신의 컴퓨터에 표시되는 출력을 복사합니다.

이제 해당 컨테이너 ID, Docker Hub 사용자 이름 및 이미지 이름을 사용하여 커밋합니다. 여기서는 "apache\를 사용합니다.

docker commit 1db0c9a40c0d user_name/apache

새 이미지를 Docker Hub로 푸시합니다.

docker push user_name/apache

이제 서비스 파일에서 이 이미지를 사용할 수 있습니다.

Apache 서비스 템플릿 단위 파일 생성

이제 컨테이너를 사용할 수 있으므로 fleetsystemd가 서비스를 올바르게 관리할 수 있도록 템플릿 단위 파일을 만들 수 있습니다.

시작하기 전에 정리된 상태를 유지할 수 있도록 디렉터리 구조를 설정해 보겠습니다.

cd ~
mkdir static templates instances

이제 templates 디렉토리 내에 템플릿 파일을 만들 수 있습니다.

vim templates/apache@.service

다음 정보를 파일에 붙여넣습니다. 유연한 플릿 단위 파일 생성에 대한 이전 가이드를 따라 사용 중인 각 옵션에 대한 세부 정보를 얻을 수 있습니다.

[Unit]
Description=Apache web server service on port %i

# Requirements
Requires=etcd.service
Requires=docker.service
Requires=apache-discovery@%i.service

# Dependency ordering
After=etcd.service
After=docker.service
Before=apache-discovery@%i.service

[Service]
# Let processes take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill apache.%i
ExecStartPre=-/usr/bin/docker rm apache.%i
ExecStartPre=/usr/bin/docker pull user_name/apache
ExecStart=/usr/bin/docker run --name apache.%i -p ${COREOS_PRIVATE_IPV4}:%i:80 \
user_name/apache /usr/sbin/apache2ctl -D FOREGROUND

# Stop
ExecStop=/usr/bin/docker stop apache.%i

[X-Fleet]
# Don't schedule on the same machine as other Apache instances
Conflicts=apache@*.service

여기서 한 가지 수정 사항은 공용 인터페이스 대신 개인 인터페이스를 사용하는 것입니다. 모든 Apache 인스턴스는 개방형 웹에서 연결을 처리하는 대신 Nginx 리버스 프록시를 통해 트래픽을 전달하므로 이는 좋은 생각입니다. DigitalOcean에서 비공개 인터페이스를 사용하는 경우 생성한 서버에 "사설 네트워킹\ 플래그가 선택되어 있어야 합니다.

또한 Docker 파일을 올바르게 풀다운하려면 Docker Hub 사용자 이름을 참조하도록 user_name을 변경해야 합니다.

Sidekick 템플릿 단위 파일 만들기

이제 sidekick 서비스에 대해 동일한 작업을 수행합니다. 이것은 나중에 필요할 정보를 예상하여 약간 수정할 것입니다.

편집기에서 템플릿 파일을 엽니다.

vim templates/apache-discovery@.service

이 파일에서 다음 정보를 사용합니다.

[Unit]
Description=Apache web server on port %i etcd registration

# Requirements
Requires=etcd.service
Requires=apache@%i.service

# Dependency ordering and binding
After=etcd.service
After=apache@%i.service
BindsTo=apache@%i.service

[Service]

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Start
## Test whether service is accessible and then register useful information
ExecStart=/bin/bash -c '\
  while true; do \
    curl -f ${COREOS_PRIVATE_IPV4}:%i; \
    if [ $? -eq 0 ]; then \
      etcdctl set /services/apache/${COREOS_PRIVATE_IPV4} \'${COREOS_PRIVATE_IPV4}:%i\' --ttl 30; \
    else \
      etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}; \
    fi; \
    sleep 20; \
  done'

# Stop
ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PRIVATE_IPV4}

[X-Fleet]
# Schedule on the same machine as the associated Apache service
MachineOf=apache@%i.service

위의 구성은 이전 가이드의 구성과 몇 가지 차이점이 있습니다. etcdctl set 명령으로 설정한 값을 조정했습니다. JSON 개체를 전달하는 대신 간단한 IP 주소 + 포트 조합을 설정하고 있습니다. 이렇게 하면 이 값을 직접 읽어 이 서비스에 도달하는 데 필요한 연결 정보를 찾을 수 있습니다.

또한 다른 파일에서와 마찬가지로 개인 인터페이스를 지정하도록 정보를 조정했습니다. 이 옵션을 사용할 수 없는 경우 공개로 두십시오.

서비스 인스턴스화

이제 이러한 서비스의 인스턴스 두 개를 만들어 보겠습니다.

먼저 심볼릭 링크를 만들어 봅시다. 생성한 ~/instances 디렉토리로 이동하고 링크하여 실행할 포트를 정의합니다. 포트 7777에서 하나의 서비스를 실행하고 포트 8888에서 다른 서비스를 실행하려고 합니다.

cd ~/instances
ln -s ../templates/apache@.service apache@7777.service
ln -s ../templates/apache@.service apache@8888.service
ln -s ../templates/apache-discovery@.service apache-discovery@7777.service
ln -s ../templates/apache-discovery@.service apache-discovery@8888.service

이제 ~/instances 디렉터리를 fleet에 전달하여 이러한 서비스를 시작할 수 있습니다.

fleetctl start ~/instances/*

인스턴스가 시작된 후(몇 분 정도 걸릴 수 있음) 사이드킥이 만든 etcd 항목을 볼 수 있어야 합니다.

etcdctl ls --recursive /
/coreos.com
/coreos.com/updateengine
/coreos.com/updateengine/rebootlock
/coreos.com/updateengine/rebootlock/semaphore
/services
/services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212

이러한 항목 중 하나의 값을 요청하면 IP 주소와 포트 번호를 받는 것을 볼 수 있습니다.

etcdctl get /services/apache/10.132.249.206
10.132.249.206:8888

curl을 사용하여 페이지를 검색하고 제대로 작동하는지 확인할 수 있습니다. 개인 네트워킹을 사용하도록 서비스를 구성한 경우에만 컴퓨터 내에서 작동합니다.

curl 10.132.249.206:8888
<h1>Running from Docker on CoreOS</h1>

이제 백엔드 인프라가 설정되었습니다. 다음 단계는 confd에 익숙해져 etcd/services/apache 위치에서 변경 사항을 확인하고 매번 Nginx를 재구성하는 것입니다. .

Nginx 컨테이너 생성

Apache 서비스에 사용한 것과 동일한 Ubuntu 14.04 기반에서 Nginx 컨테이너를 시작합니다.

소프트웨어 설치

다음을 입력하여 새 컨테이너를 시작합니다.

docker run -i -t ubuntu:14.04 /bin/bash

로컬 apt 패키지 캐시를 업데이트하고 Nginx를 설치합니다. 또한 기본 이미지에 curl이 포함되어 있지 않기 때문에 curl을 설치해야 하며 잠시 동안 GitHub에서 안정적인 confd 패키지를 가져와야 합니다.

apt-get update
apt-get install nginx curl -y

이제 v0.5.0으로 갈 수 있지만 이것이 변경되었을 수 있습니다. 도구의 Linux 버전에 대한 링크를 마우스 오른쪽 버튼으로 클릭하고 "링크 주소 복사\ 또는 사용 가능한 유사한 옵션을 선택합니다.

이제 Docker 컨테이너로 돌아가 복사된 URL을 사용하여 애플리케이션을 다운로드합니다. 이것을 /usr/local/bin 디렉토리에 넣을 것입니다. 출력 파일로 confd를 선택해야 합니다.

cd /usr/local/bin
curl -L https://github.com/kelseyhightower/confd/releases/download/v0.5.0/confd-0.5.0<^>-linux-amd64 -o confd

이제 컨테이너 내에서 사용할 수 있도록 파일을 실행 가능하게 만듭니다.

chmod +x confd

또한 이 기회를 이용하여 confd가 기대하는 구성 구조를 만들어야 합니다. 이것은 /etc 디렉토리 내에 있습니다:

mkdir -p /etc/confd/{conf.d,templates}

Etcd 값을 읽기 위한 Confd 구성 파일 만들기

이제 응용 프로그램을 설치했으므로 confd 구성을 시작해야 합니다. 구성 파일 또는 템플릿 리소스 파일을 생성하여 시작하겠습니다.

confd의 구성 파일은 특정 etcd 값을 확인하고 변경 사항이 감지되면 작업을 시작하도록 서비스를 설정하는 데 사용됩니다. 이들은 사용하기 쉽고 상당히 직관적인 TOML 파일 형식을 사용합니다.

nginx.toml이라는 구성 디렉토리 내에 파일을 생성하여 시작합니다.

vi /etc/confd/conf.d/nginx.toml

여기에 구성 파일을 구축합니다. 다음 정보를 추가합니다.

[template]

# The name of the template that will be used to render the application's configuration file
# Confd will look in `/etc/conf.d/templates` for these files by default
src = "nginx.tmpl"

# The location to place the rendered configuration file
dest = "/etc/nginx/sites-enabled/app.conf"

# The etcd keys or directory to watch.  This is where the information to fill in
# the template will come from.
keys = [ "/services/apache" ]

# File ownership and mode information
owner = "root"
mode = "0644"

# These are the commands that will be used to check whether the rendered config is
# valid and to reload the actual service once the new config is in place
check_cmd = "/usr/sbin/nginx -t"
reload_cmd = "/usr/sbin/service nginx reload"

위의 파일에는 몇 가지 기본 아이디어를 설명하는 주석이 있지만 아래에 있는 옵션을 검토할 수 있습니다.

Directive Required? Type Description
src Yes String The name of the template that will be used to render the information. If this is located outside of /etc/confd/templates, the entire path is should be used.
dest Yes String The file location where the rendered configuration file should be placed.
keys Yes Array of strings The etcd keys that the template requires to be rendered correctly. This can be a directory if the template is set up to handle child keys.
owner No String The username that will be given ownership of the rendered configuration file.
group No String The group that will be given group ownership of the rendered configuration file.
mode No String The octal permissions mode that should be set for the rendered file.
check_cmd No String The command that should be used to check the syntax of the rendered configuration file.
reload_cmd No String The command that should be used to reload the configuration of the application.
prefix No String A part of the etcd hierarchy that comes before the keys in the keys directive. This can be used to make the .toml file more flexible.

우리가 만든 파일은 confd 인스턴스가 어떻게 작동할지에 대한 몇 가지 중요한 정보를 알려줍니다. Nginx 컨테이너는 /etc/confd/templates/nginx.conf.tmpl에 저장된 템플릿을 사용하여 /etc/nginx/sites-enabled/에 배치될 구성 파일을 렌더링합니다. app.conf. 파일에는 0644 권한 집합이 부여되고 소유권은 루트 사용자에게 부여됩니다.

confd 애플리케이션은 /services/apache 노드에서 변경 사항을 찾습니다. 변경 사항이 확인되면 confd는 해당 노드 아래의 새 정보를 쿼리합니다. 그런 다음 Nginx에 대한 새 구성을 렌더링합니다. 구성 파일에서 구문 오류를 확인하고 파일이 제자리에 있으면 Nginx 서비스를 다시 로드합니다.

이제 템플릿 리소스 파일이 생성되었습니다. Nginx 구성 파일을 렌더링하는 데 사용할 실제 템플릿 파일에 대해 작업해야 합니다.

Confd 템플릿 파일 생성

템플릿 파일의 경우 confd 프로젝트의 GitHub 설명서에 있는 예제를 사용하여 시작할 것입니다.

위의 구성 파일에서 참조한 파일을 만듭니다. 이 파일을 templates 디렉터리에 넣습니다.

vi /etc/confd/templates/nginx.tmpl

이 파일에서는 기본적으로 표준 Nginx 리버스 프록시 구성 파일을 다시 만듭니다. 그러나 일부 Go 템플릿 구문을 사용하여 confdetcd에서 가져오는 일부 정보를 대체할 것입니다.

먼저 "업스트림\ 서버로 블록을 구성합니다. 이 섹션은 Nginx가 요청을 보낼 수 있는 서버 풀을 정의하는 데 사용됩니다. 형식은 일반적으로 다음과 같습니다.

upstream pool_name {
    server server_1_IP:port_num;
    server server_2_IP:port_num;
    server server_3_IP:port_num;
}

이를 통해 pool_name에 요청을 전달할 수 있으며 Nginx는 요청을 전달할 정의된 서버 중 하나를 선택합니다.

템플릿 파일의 기본 아이디어는 Apache 웹 서버의 IP 주소와 포트 번호에 대해 etcd를 구문 분석하는 것입니다. 따라서 업스트림 서버를 정적으로 정의하는 대신 파일이 렌더링될 때 이 정보를 동적으로 채워야 합니다. 동적 콘텐츠에 Go 템플릿을 사용하여 이를 수행할 수 있습니다.

이를 위해 대신 다음을 블록으로 사용합니다.

upstream apache_pool {
{{ range getvs "/services/apache/*" }}
    server {{ . }};
{{ end }}
}

무슨 일이 일어나고 있는지 잠시 설명하겠습니다. 우리는 apache_pool이라는 서버의 업스트림 풀을 정의하기 위해 블록을 열었습니다. 내부에서 이중 괄호를 사용하여 일부 Go 언어 코드를 시작한다고 지정합니다.

이 대괄호 안에 관심 있는 값이 보관되는 etcd 끝점을 지정합니다. 목록을 반복 가능하게 만들기 위해 범위를 사용하고 있습니다.

이를 사용하여 etcd/services/apache 위치 아래에서 검색된 모든 항목을 range 블록으로 전달합니다. 그런 다음 삽입된 값을 나타내는 "{{\ 및 "}}\ 내의 단일 점을 사용하여 현재 반복에서 키 값을 가져올 수 있습니다. 범위 루프 내에서 이것을 사용하여 서버 풀을 채웁니다. 마지막으로 {{ end }} 지시문으로 루프를 종료합니다.

참고: 루프 내에서 server 지시문 뒤에 세미콜론을 추가해야 합니다. 이것을 잊어버리면 작동하지 않는 구성이 됩니다.

서버 풀을 설정한 후 프록시 패스를 사용하여 모든 연결을 해당 풀로 보낼 수 있습니다. 이것은 리버스 프록시로서의 표준 서버 블록일 뿐입니다. 한 가지 주목해야 할 것은 access_log인데, 이는 우리가 잠시 생성할 사용자 지정 형식을 사용합니다.

upstream apache_pool {
{{ range getvs "/services/apache/*" }}
    server {{ . }};
{{ end }}
}

server {
	listen 80 default_server;
	listen [::]:80 default_server ipv6only=on;

    access_log /var/log/nginx/access.log upstreamlog;

    location / {
        proxy_pass http://apache_pool;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

이것은 포트 80의 모든 연결에 응답하고 etcd 항목을 보고 생성된 apache_pool의 서버 풀로 전달합니다.

서비스의 이러한 측면을 처리하는 동안 나중에 충돌이 발생하지 않도록 기본 Nginx 구성 파일을 제거해야 합니다. 기본 구성을 활성화하는 심볼릭 링크만 제거합니다.

rm /etc/nginx/sites-enabled/default

이제 템플릿 파일에서 참조한 로그 형식을 구성할 적기이기도 합니다. 기본 구성 파일에서 사용할 수 있는 구성의 http 블록에 들어가야 합니다. 지금 열기:

vi /etc/nginx/nginx.conf

기록하려는 정보를 정의하기 위해 log_format 지시문을 추가합니다. 방문 중인 클라이언트와 요청이 전달되는 백엔드 서버를 기록합니다. 이러한 절차에 걸리는 시간에 대한 일부 데이터를 기록합니다.

. . .
http {
    ##
    # Basic Settings
    ##
    log_format upstreamlog '[$time_local] $remote_addr passed to: $upstream_addr: $request Upstream Response Time: $upstream_response_time Request time: $request_time';

    sendfile on;
    . . .

완료되면 파일을 저장하고 닫습니다.

Confd를 실행할 스크립트 만들기

적절한 시간에 템플릿 리소스 파일과 템플릿 파일로 confd를 호출할 스크립트 파일을 만들어야 합니다.

서비스가 올바르게 작동하려면 스크립트가 두 가지 작업을 수행해야 합니다.

  • 백엔드 인프라의 현재 상태를 기반으로 초기 Nginx 설정을 설정하기 위해 컨테이너가 시작될 때 실행되어야 합니다.
  • 사용 가능한 백엔드 서버를 기반으로 Nginx를 재구성할 수 있도록 Apache 서버에 대한 etcd 등록의 변경 사항을 계속 감시해야 합니다.

Marcel de Graaf의 GitHub 페이지에서 스크립트를 가져옵니다. 이것은 우리가 필요로 하는 것을 정확하게 수행하는 멋지고 간단한 스크립트입니다. 우리는 시나리오를 약간만 편집할 것입니다.

이 스크립트를 confd 실행 파일 옆에 두겠습니다. 우리는 이것을 confd-watch라고 부를 것입니다:

vi /usr/local/bin/confd-watch

기존의 bash 헤더부터 시작하여 필요한 인터프리터를 식별합니다. 그런 다음 문제가 발생하면 스크립트가 즉시 실패하도록 몇 가지 bash 옵션을 설정합니다. 실패하거나 실행할 마지막 명령의 값을 반환합니다.

#!/bin/bash

set -eo pipefail

다음으로 몇 가지 변수를 설정하려고 합니다. bash 매개변수 대체를 사용하여 기본값을 설정하지만 스크립트를 호출할 때 하드 코딩된 값을 재정의할 수 있는 유연성을 구축합니다. 이것은 기본적으로 연결 주소의 각 구성 요소를 독립적으로 설정한 다음 함께 그룹화하여 필요한 전체 주소를 얻습니다.

매개변수 대체는 $ {var_name:-default_value} 구문으로 생성됩니다. 이것은 var_name 값이 주어지고 null이 아닌 경우 값을 사용하는 속성을 가지며, 그렇지 않으면 default_value로 기본 설정됩니다.

etcd가 기본적으로 기대하는 값을 기본값으로 설정하고 있습니다. 이렇게 하면 추가 정보 없이 스크립트가 제대로 작동할 수 있지만 스크립트를 호출할 때 필요에 따라 사용자 지정할 수 있습니다.

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

이제 confd를 사용하여 이 스크립트가 호출될 때 사용 가능한 etcd에서 값을 읽어 Nginx 구성 파일의 초기 버전을 렌더링합니다. until 루프를 사용하여 지속적으로 초기 구성을 빌드하려고 합니다.

루핑 구성은 etcd를 즉시 사용할 수 없거나 Nginx 컨테이너가 백엔드 서버보다 먼저 온라인 상태가 되는 경우에 필요할 수 있습니다. 이렇게 하면 최종적으로 유효한 초기 구성을 생성할 수 있을 때까지 etcd를 반복적으로 폴링할 수 있습니다.

우리가 호출하는 실제 confd 명령은 한 번 실행된 다음 종료됩니다. 이는 백엔드 서버에 등록할 기회를 주기 위해 다음 실행까지 5초를 기다릴 수 있도록 하기 위한 것입니다. 기본값을 사용하여 빌드하거나 매개변수를 전달한 전체 ETCD 변수에 연결하고 템플릿 리소스 파일을 사용하여 원하는 동작을 정의합니다.

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

echo "[nginx] booting container. ETCD: $ETCD"

# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; do
    echo "[nginx] waiting for confd to create initial nginx configuration"
    sleep 5
done

초기 구성이 설정된 후 스크립트의 다음 작업은 지속적인 폴링을 위한 메커니즘을 배치하는 것입니다. Nginx가 업데이트되도록 향후 변경 사항이 감지되는지 확인하고 싶습니다.

이를 위해 confd를 한 번 더 호출할 수 있습니다. 이번에는 연속 폴링 간격을 설정하고 무한정 실행되도록 프로세스를 백그라운드에 배치하려고 합니다. 우리의 목표는 여전히 동일하므로 동일한 etcd 연결 정보와 동일한 템플릿 리소스 파일을 전달합니다.

confd 프로세스를 백그라운드로 둔 후 생성된 구성 파일을 사용하여 Nginx를 안전하게 시작할 수 있습니다. 이 스크립트는 Docker "run\ 명령으로 호출될 것이므로 컨테이너가 이 시점에서 종료되지 않도록 포그라운드에서 계속 실행해야 합니다. 우리가 기록해 온 모든 정보:

#!/bin/bash

set -eo pipefail

export ETCD_PORT=${ETCD_PORT:-4001}
export HOST_IP=${HOST_IP:-172.17.42.1}
export ETCD=$HOST_IP:$ETCD_PORT

echo "[nginx] booting container. ETCD: $ETCD."

# Try to make initial configuration every 5 seconds until successful
until confd -onetime -node $ETCD -config-file /etc/confd/conf.d/nginx.toml; do
    echo "[nginx] waiting for confd to create initial nginx configuration."
    sleep 5
done

# Put a continual polling `confd` process into the background to watch
# for changes every 10 seconds
confd -interval 10 -node $ETCD -config-file /etc/confd/conf.d/nginx.toml &
echo "[nginx] confd is now monitoring etcd for changes..."

# Start the Nginx service using the generated config
echo "[nginx] starting nginx service..."
service nginx start

# Follow the logs to allow the script to continue running
tail -f /var/log/nginx/*.log

이 작업을 마치면 파일을 저장하고 닫습니다.

마지막으로 해야 할 일은 스크립트를 실행 가능하게 만드는 것입니다.

chmod +x /usr/local/bin/confd-watch

지금 컨테이너를 종료하여 호스트 시스템으로 돌아갑니다.

exit

컨테이너 커밋 및 푸시

이제 컨테이너를 커밋하고 Docker 허브로 푸시하여 머신에서 풀다운할 수 있도록 할 수 있습니다.

컨테이너 ID를 찾으십시오.

docker ps -l
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                          PORTS               NAMES
de4f30617499        ubuntu:14.04        "/bin/bash"         22 hours ago        Exited (0) About a minute ago                       stupefied_albattani

강조 표시된 문자열은 필요한 컨테이너 ID입니다. Docker Hub 사용자 이름 및 이 이미지에 사용할 이름과 함께 이 ID를 사용하여 컨테이너를 커밋합니다. 이 가이드에서는 "nginx_lb\라는 이름을 사용할 것입니다.

docker commit de4f30617499 user_name/nginx_lb

필요한 경우 Docker Hub 계정에 로그인합니다.

docker login

이제 다른 호스트가 필요에 따라 풀다운할 수 있도록 커밋된 이미지를 푸시업해야 합니다.

docker push user_name/nginx_lb

Nginx 정적 단위 파일 빌드

다음 단계는 방금 만든 컨테이너를 시작할 단위 파일을 빌드하는 것입니다. 이렇게 하면 fleet을 사용하여 프로세스를 제어할 수 있습니다.

이것은 템플릿이 아니므로 이 디렉터리의 시작 부분에서 만든 ~/static 디렉터리에 넣습니다.

vim static/nginx_lb.service

표준 [Unit] 섹션부터 시작하여 서비스를 설명하고 종속성과 순서를 정의합니다.

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

다음으로 파일의 [Service] 부분을 정의해야 합니다. 아파치 서비스 파일에서 했던 것처럼 타임아웃을 0으로 설정하고 killmode를 다시 없음으로 조정합니다. 이 컨테이너가 실행 중인 호스트의 퍼블릭 및 프라이빗 IP 주소에 액세스할 수 있도록 환경 파일을 다시 가져옵니다.

그런 다음 이 컨테이너의 이전 버전이 종료되고 제거되도록 환경을 정리합니다. 항상 최신 버전을 유지하기 위해 방금 만든 컨테이너를 풀다운합니다.

마지막으로 컨테이너를 시작합니다. 여기에는 컨테이너를 시작하고 제거 및 종료 명령에서 참조한 이름을 지정하고 실행 중인 호스트의 공용 IP 주소를 포트 80에 매핑하는 작업이 포함됩니다. 우리는 confd-watch 를 호출합니다. 실행 명령으로 작성한 스크립트입니다.

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lb
ExecStartPre=-/usr/bin/docker rm nginx_lb
ExecStartPre=/usr/bin/docker pull user_name/nginx_lb
ExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \
user_name/nginx_lb /usr/local/bin/confd-watch

이제 우리가 정리해야 할 것은 정지 명령과 함대 일정 지시뿐입니다. 우리는 이 컨테이너가 다른 로드 밸런싱 인스턴스 또는 백엔드 Apache 서버를 실행하지 않는 호스트에서만 시작되기를 원합니다. 이렇게 하면 서비스가 로드를 효과적으로 분산할 수 있습니다.

[Unit]
Description=Nginx load balancer for web server backends

# Requirements
Requires=etcd.service
Requires=docker.service

# Dependency ordering
After=etcd.service
After=docker.service

[Service]
# Let the process take awhile to start up (for first run Docker containers)
TimeoutStartSec=0

# Change killmode from "control-group" to "none" to let Docker remove
# work correctly.
KillMode=none

# Get CoreOS environmental variables
EnvironmentFile=/etc/environment

# Pre-start and Start
## Directives with "=-" are allowed to fail without consequence
ExecStartPre=-/usr/bin/docker kill nginx_lb
ExecStartPre=-/usr/bin/docker rm nginx_lb
ExecStartPre=/usr/bin/docker pull user_name/nginx_lb
ExecStart=/usr/bin/docker run --name nginx_lb -p ${COREOS_PUBLIC_IPV4}:80:80 \
user_name/nginx_lb /usr/local/bin/confd-watch

# Stop
ExecStop=/usr/bin/docker stop nginx_lb

[X-Fleet]
Conflicts=nginx.service
Conflicts=apache@*.service

완료되면 파일을 저장하고 닫습니다.

Nginx 로드 밸런서 실행

튜토리얼의 앞부분에서 실행 중인 두 개의 Apache 인스턴스가 이미 있어야 합니다. 다음을 입력하여 확인할 수 있습니다.

fleetctl list-units
UNIT				MACHINE				ACTIVE	SUB
apache-discovery@7777.service	197a1662.../10.132.249.206	active	running
apache-discovery@8888.service	04856ec4.../10.132.249.212	active	running
apache@7777.service		197a1662.../10.132.249.206	active	running
apache@8888.service		04856ec4.../10.132.249.212	active	running

다음을 입력하여 etcd에 올바르게 등록하고 있는지 다시 확인할 수도 있습니다.

etcdctl ls --recursive /services/apache
/services/apache/10.132.249.206
/services/apache/10.132.249.212

이제 Nginx 서비스를 시작할 수 있습니다.

fleetctl start ~/static/nginx_lb.service
Unit nginx_lb.service launched on 96ec72cf.../10.132.248.177

이미지를 풀다운하는 데 걸리는 시간에 따라 서비스가 시작되는 데 1분 정도 걸릴 수 있습니다. 시작된 후 fleetctl journal 명령으로 로그를 확인하면 confd에서 일부 로그 정보를 볼 수 있어야 합니다. 다음과 같아야 합니다.

fleetctl journal nginx_lb.service
-- Logs begin at Mon 2014-09-15 14:54:05 UTC, end at Tue 2014-09-16 17:13:58 UTC. --
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[14]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated
Sep 16 17:13:48 lala1 docker[15379]: [nginx] confd is monitoring etcd for changes...
Sep 16 17:13:48 lala1 docker[15379]: [nginx] starting nginx service...
Sep 16 17:13:48 lala1 docker[15379]: 2014-09-16T17:13:48Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/access.log <==
Sep 16 17:13:48 lala1 docker[15379]: ==> /var/log/nginx/error.log <==
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO /etc/nginx/sites-enabled/app.conf has md5sum a8517bfe0348e9215aa694f0b4b36c9b should be 33f42e3b7cc418f504237bea36c8a03e
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf out of sync
Sep 16 17:13:58 lala1 docker[15379]: 2014-09-16T17:13:58Z d7974a70e976 confd[33]: INFO Target config /etc/nginx/sites-enabled/app.conf has been updated

보시다시피 confd는 초기 구성을 위해 etcd를 찾았습니다. 그런 다음 nginx를 시작했습니다. 그런 다음 etcd 항목이 재평가되고 새 구성 파일이 만들어진 줄을 볼 수 있습니다. 새로 생성된 파일이 파일의 md5sum과 일치하지 않으면 파일이 전환되고 서비스가 다시 로드됩니다.

이를 통해 로드 밸런싱 서비스는 궁극적으로 Apache 백엔드 서버를 추적할 수 있습니다. confd가 지속적으로 업데이트되는 것 같으면 Apache 인스턴스가 TTL을 너무 자주 새로 고치기 때문일 수 있습니다. 이를 방지하기 위해 사이드킥 템플릿에서 절전 및 TTL 값을 늘릴 수 있습니다.

작동 중인 로드 밸런서를 보려면 Nginx 서비스를 실행 중인 호스트에서 /etc/environments 파일을 요청할 수 있습니다. 여기에는 호스트의 공용 IP 주소가 포함됩니다. 이 구성을 개선하려면 Apache 인스턴스에 대해 수행한 것처럼 이 정보를 etcd에 등록하는 사이드킥 서비스를 실행하는 것이 좋습니다.

fleetctl ssh nginx_lb cat /etc/environment
COREOS_PRIVATE_IPV4=10.132.248.177
COREOS_PUBLIC_IPV4=104.131.16.222

이제 브라우저에서 퍼블릭 IPv4 주소로 이동하면 Apache 인스턴스에서 구성한 페이지가 표시됩니다.

이제 로그를 다시 보면 어떤 백엔드 서버가 실제로 요청을 전달했는지 나타내는 정보를 볼 수 있습니다.

fleetctl journal nginx_lb
. . .
Sep 16 18:04:38 lala1 docker[18079]: 2014-09-16T18:04:38Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: 2014-09-16T18:04:48Z 51c74658196c confd[28]: INFO Target config /etc/nginx/sites-enabled/app.conf in sync
Sep 16 18:04:48 lala1 docker[18079]: [16/Sep/2014:18:04:48 +0000] 108.29.37.206 passed to: 10.132.249.212:8888: GET / HTTP/1.1 Upstream Response Time: 0.003 Request time: 0.003

결론

보시다시피 etcd에서 구성 세부 정보를 확인하도록 서비스를 설정할 수 있습니다. confd와 같은 도구는 중요한 항목의 지속적인 폴링을 허용하여 이 프로세스를 상대적으로 간단하게 만들 수 있습니다.

이 가이드의 예에서는 etcd를 사용하여 초기 구성을 생성하도록 Nginx 서비스를 구성했습니다. 또한 백그라운드에서 변경 사항을 지속적으로 확인하도록 설정했습니다. 이것은 템플릿 기반의 동적 구성 생성과 결합되어 백엔드 서버의 최신 그림을 일관되게 유지할 수 있게 해주었습니다.