Ansible, ec2.py 를 이용한 Dynamic Inventory 활용

Ansible 에는 접속 정보와 관련된 정보들을 Inventory 라고 부른다. 접속 호스트, 접속 계정 정보뿐만 아니라 이들을 그룹으로 묶거나 변수 설정도 가능하다.

그런데, 클라우드 시스템과 같이 서버 관련 정보를 API 형식으로 제공할 경우에 일일이 호스트 정보를 파일로 저장할 필요가 없다. 클라우드 시스템에 서버 관련 정보를 호출하며 자동으로 Inventory 정보가 생성되는 기능을 제공하는데 이를 Dynamic Inventory 라고 한다. 이 기능은 클라우드 뿐만 아니라 LDAP 과 같은 인증 시스템에도 활용가능하다.

Ansible 세팅

AWS 클라우드의 Dynamic Inventory를 활용하기 위한 Ansible 을 세팅해 보자. 가장 중요한 ansible.cfg 는 다음과 같다.

특별히 inventory 에는 AWS 클라우드에 제공하는 Dynamic Inventory 스크립트 위치를 지정해준다. ansible 을 이용한 접속 정보, 실행할 계정에 대한 정보등을 기재한다.

디렉토리는 구조는 대략 다음과 같다.

AWS 클라우드 Dynamic Inventory 파일

AWS 클라우드의 경우에도 Ansible 의 Dinamic Inventory 기능을 제공한다. 작동원리는 AWS 자원 정보를 불러오고 이것을 Ansible 이 인식하는 Inventory 정보를 구성하는 것이다. AWS 자원 정보를 불러오기 위해서 AWS 는 다음과 같은 스크립트와 환경설정 정보를 제공한다.

ec2.py 는 AWS 클라우드 시스템에 호스트 관련 정보를 불러오도록 한다. ec2.ini 는 어디, 어떤 정보를 불러올 건지 어떤 내용을 출력할 것인지를 지정할 수가 있다. 예를들면 다음과 같다.

regions 이 기본값은 all 이다. 이러면 모든 리전에 대해서 호스트 정보를 수집할려고 하기 때문에 시간이 오래걸리는 문제가 발생한다. 특정한 리전에 대해서만 수행하도록 지정하는 것이 좋다.

IAM 설정

가장 중요한것이 IAM 설정이다. Ansible 을 실행하는 서버에는 호스트 정보를 불러올수 있는 IAM 권한이 필요하다. 보통 IAM Role 지정이라고 하는데 대략 다음과 같은 Policy 를 만들어 Role 적용을 하면 된다.

Access Key, Secret key 를 이용하는 방법도 있지만 권장하지 않는다.

ec2.py 테스트 및 특징

이제 요건이 갖춰졌으니 테스트를 해보자.

내용을 보면 위와같은 key 값들을 보게 된다. 집작했겠지만 ec2.py 는 ec2 인스턴스의 tag 를 key 로 지정해준다. tag 뿐만 아니라 ec2 인스턴스의 정보를 key 만들어준다.

이 key들은 Ansible Inventory 의 group 변수로 활용이 가능하다.

ec2 key pair 를 이용한 접속 정보 만들기

ec2.py 에서 key 들은 곧바로 Ansible 의 group 으로 활용 가능하다. 이를 위해서 inventory/production/group_vars 디렉토리에 key 이름으로 yaml 파일을 생성한다. 그리고 다음과 같이 내용을 입력한다.

Ansible이 그룹 접속을 할때에 위 변수를 활용하게 된다. AWS 클라우드 ec2 접속하기 위한 keypair 를 이용하는데 따른 설정이다.

접속 테스트

이제 다 됐다. 다음과 같이 접속 테스트를 한번 해본다.

위와같이 나오면 성공한 것이다.

Grub2 에 기본 커널 지정하기

Grub2 은 리눅스 시스템의 부팅 메니져이다. 리눅스는 커널을 여러개를 설치하고 부팅시에 선택해서 원하는 커널로 부팅을 할 수 있도록 해준다. 비상 복구가 필요할 경우에도 부팅 메니져인 Grub2 에서 비상복구 모드를 선택하면 된다.

문제는 어떻게 기본 커널을 지정할 수 있을까?

먼저, 기본 부팅 커널은 다음과 같이 확인할 수 있다.

만일 부팅 상황이라면 위에 설정한 커널을 기본으로 부팅을 진행하게 된다. 만일 이 기본 커널을 변경하고자 할 경우에는 어떻게 할까?

우선, 현재 Grub2 에 등록된 커널 목록들을 알아야하는데 다음과 같이 하면 알 수 있다.

커널 목록을 확인할 수 있는데, 맨 위쪽부터 0 을 시작으로 번호를 붙일 수 있다. 이러한 번호는 기본 부팅 커널을 바꾸는데 유용하게 사용된다. 이제 기본 부팅 커널을 다음과 같이 바꿀 수 있다.

확인을 한번 해보면 다음과 같다.

이렇게 한 후에 다시 Grub 을 설치해줘야 한다.

정상적으로 되었다면 기본 부팅 커널이 바꾼 것이다.

AMAZON S3 버킷 램덤화 객체 접두사 불 필요.

과거에 AMAZON S3 버킷 성능 끌어올리기 라는 글을 통해서 S3를 사용하는데 있어서 성능향상 방법에 대해서 설명한 적이 있다. 핵심은 객체 접두사를 램덤화해서 S3에 올라가는 파일들이 균일하게 넓게 퍼질 수 있도록 해야한다는 것이였다.

하지만 2018년 7월 17일에 AWS 에서는 S3에 성능향상을 언급하면서 이제 객체 접두사의 랜덤화는 불필요하다고 말했다.

Amazon S3, 요청 처리 성능 개선 발표

이 같은 S3 요청 처리 성능 향상으로 인해 객체 접두사를 랜덤화하여 더 빠른 성능을 실현하라는 이전의 지침은 더 이상 적용되지 않습니다. 즉, 이제 성능 저하 없이 S3 객체에 논리적 또는 순차적 명명 패턴을 사용할 수 있습니다. 이 성능 향상은 이제 모든 AWS 리전에서 제공됩니다. 자세한 내용은 Amazon S3 개발자 가이드를 참조하십시오.

이제 S3 버킷에서 객체를 저장할때 접두사를 램덤화하려는 고민을 하지 않아도 된다.

Tomat 8.5 Manager 패스워드 암호화 하기

Tomcat 8 로 넘어오면서 manager 페이지 접근을 위한 패스워드 암호화 방법에 조금 변화가 있었다. 이에 대해서 기술한다.

Manager 페이지 접근 권한 – context.xml

기본값으로 /manager 페이지에 대한 접근은 localhost 로 제한이 걸려 있다. 이것은 manager 앱에 대한 context.xml 파일에 설정되어 있는 내용인데, 파일 경로는 $CATALINA_HOME/webpps/manager/META-INF/context.xml 이다. 다음과 같이 접근 제한된 부분에서 외부접속을 위한 설정을 해준다.

Valve 를 이용해서 RemoteAddrValve 에 대해서 접근 아이피 주소가 적혀 있다. 여기서는 접근 제한을 해제해주고 있다. 하지만 product 환경에서는 절대로 이렇게 하지말고 접근 가능한 IP 주소를 입력해주도록 하자.

암호화 알고리즘 정의 – server.xml

암호화 알고리즘에는 md5, sha-256, sha-512 등을 지정할 수 있다. 이를 위해서 server.xml 을 수정해 줘야 한다.

CredentialHandler 를 통해서 algorithm을 SHA-256 으로 정의해주고 있다. 중요한 것은 어디다가 해주냐하는 것임으로 위에 예제를 유심히 보고 정확한 위치에 이를 추가해줘야 한다.

암호화된 스트링 얻기 – digest.sh

이제 암호화된 스트링을 얻어야 한다. 이는 $CATALINA_HOME/bin/digest.sh 스크립트를 이용해서 손쉽게 얻을 수 있다. 주의할 것은 암호화 알고리즘에 맞는 암호화된 스트링을 얻기위해서 알고리즘을 옵션으로 알려줘야 한다.

결과에서 콜론(:)을 기준으로 앞은 평문 문자열, 뒤는 암호화된 문자열을 보여준다.

manager 인증 설정 – tomcat-users.xml

이제 manager 인증을 위한 설정을 해준다. 이는 tomcat-users.xml 해주는데, 다음과 같이 해준다.

위와 같이 암호화된 스트링을 password 인자로 주면 된다.

이렇게 Tomcat 8.5 에 대한 /manager 인증 암호 문자열 암호화 하기에 대해 알아 봤다.

Traefik, Portainer, Registry 를 위한 Docker Compose

docker-compose.yml 파일 내용은 다음과 같다.

위와같이 내용을 작성하고 YAML 파일로 저장한다. 저장한 파일 이름이 docker-frontend.yml 이라고 한다면 이것을 이용해서 다음과 같이 docker stack 을 deploy 한다.

stack 이 생성 정상적으로 생성되면 3개의 Service가 생성된다. 각각 Traefik, Portainer, Registry 이며 Portainer 는 Traefik 에 URI Reverse 로 연결된다. Portainer 의 URL 은 http://<IP>/portainer 이다.

Registry 에 .htpasswd 파일은 다음과 같이 생성하면 된다.

위 내용은 Traefik 를 앞에 두고 뒤에 Portainer 를 /portainer URI 로 접속하도록 한다. registry 서비스는 Traefik 와 별도로 작동되도록 하였다.

Docker 네트워크 이해

Docker 를 단순한 빠르고 가볍게 애플리케이션을 구성하게 해주는 컨테이너(Container) 로만 이해하는 건 좁은 시각이다. Docker 는 이러한 컨테이너들을 위한 네트워크 환경도 제공하고 있다. 이것은 Docker 가 종합적인 IT 인프라를 제공할 수 있다는 것을 의미한다.

Docker 네크워크 상태

Docker 를 호스트에 설치하면 우선적으로 다음과 같은 네트워크 장치가 하나 보인다.

컨테이너를 하나도 실행하지 않은 상태에서 단지 Docker 데몬이 실행만 되어도 이렇게 docker0 라는 네트워크 장치가 나타난다. 아이피는 172.17.0.1 이며 브로드캐스트(Broadcast) 가 172.17.255.255 인 것으로 봐서 docker0 장치가 속하는 네트워크 대역은 172.17.0.0/16 임을 알 수 있다.

docker0 는 Docker 가 실행되면서 자동으로 생성되는 가상의 네트워크 장치다. 네트워크 장치에도 여러가지 역할 혹은 모드를 부여할 수 있는데, docker0 가상네트워크는 브릿지모드로 동작하도록되어 있다.

docker0 가상네트워크가 브릿지 모드로 동작한다는 것은 이 브릿지에 연결한 네트워크 장비들을 외부와 통신하도록 해준다. 말 그대로 다리 역할을 하는 것이 docker0 이다.

이제 컨테이너 하나를 생성해 보자.

우분투(Ubuntu) 컨테이너 하나를 실행했다. 이 상태에서 호스트 네트워크를 살펴보면 다음과 같다.

없었던 veth83317a4 가 생겼다. 그리고 docker0 가상네트워크의 브릿지 상태는 다음과 같다.

docker0 에 veth83317a4 가상네트워크 장치가 연결되었다는 것을 볼 수 있다. 이것은 ‘ip link’ 나 ‘ip a’ 명령어로도 확인할 수 있다.

‘master docker0’ 가 이 가상네트워크 장치가 docker0 브릿지에 연결되었다는 것을 말해준다.

우분투 컨테이너의 네트워크 상태는 어떻게 될까? 다음과 같이 확인이 가능하다.

eth0 장치가 있고, 아이피는 172.17.0.2 로 할당되어 있다. 그리고 Default Gateway 는 다음과 같이 확인할 수 있다.

우분투 컨테이너의 Default Gateway 는 컨테이너를 실행한 호스트의 Docker 가상네트워크인 docker0 를 가르키고 있다. 결국 Docker 컨테이너의 모든 네트워크는 호스트의 docker0 를 가르키고 이는 모든 외부와의 트래픽은 docker0 을 통해서만 가능하다.

이를 도식으로 나타내면 다음과 같다.

Docker 컨테이너 네트워크

Docker0 브릿지 네트워크

이 docker0 브릿지 네트워크는 Docker 네트워크중에 하나다.

Docker 가 기본으로 제공하는 네트워크 기능들이 나온다. 여기서 bridge 에 대한 내용을 자세하 살펴보면 다음과 같다.

위 내용을 보면 IPAM 에 Config 를보면 네트워크 설정 내용이 보인다. 그리고 Options 에 “com.docker.network.bridge.name”: “docker0” 라는게 보인다. 이렇게 docker0 가상네트워크가 Docker 에서 생성한 Bridge 라는 것을 알 수 있다.

또, 현재 Bridge 에 연결되 실행되는 컨테이너 네트워크 정보도 함께 알 수 있다.

Docker 네트워크 특징

도커 호스트에 있는 컨테이너를 위한 가상네트워크 장비는 컨테이너와 peer 된 상태가 된다. 컨테이너를 하나씩 실행할때마다 하나씩 늘어난다. 컨테이너 갯수에 맞춰서 존재한다는 것이다.

도커 호스트에 컨테이너를 위한 가상네트워크 장비인 veth4327b92 는 컨테이너가 재시작될때마다 veth 를 제외한 숫자가 매번 바뀐다. 우분투 컨테이너를 재시작하고 난후 vethffc000e 로 변경됐다.

또, 위 도식에 보면 컨테이너 네트워크에 12라는 숫자가 보인다. 그리고 도커 호스트에 컨테이너를 위한 가상네트워크 번호가 13으로 나온다. 이를 보면 도커 컨테이너 네트크워크 숫자는 veth 가상호스트의 숫자보다 하나 작은 값을 가진다는 것을 알 수 있다. 이 숫자도 도커 컨테이너가 재시작될때마다 바뀌지만 1 작은 상태는 그대로 유지 된다. 이로써 도커 컨테이너 네트워크가 외부에 어느 veth 네트워크와 연결되는지를 알수 있게 된다.

또, 컨테이너에서 외부의 veth 가상네트워크를 볼 수가 없다. 이는 커널의 Network Namespace 로 격리를 하기 때문이다.

Docker Network Namespace

docker 의 Network Namespace 는 Docker 컨테이너가 실행될때마다 /var/run/docker/netns 디렉토리에 생성된다. 이에 대한 정보는 컨테이너 상세정보를 보면 알 수 있다.

이제 이것을 ip netns 에서 사용할 수 있도록 심볼릭 링크를 작성해 보자.

이렇게 한 후에 netns 를 살펴보면 다음과 같은 결과가 나온다.

이것을 이용하면 네트워크 정보를 확인할 수 있다.

Network Namespace 를 통해서 컨테이너에 네트워크 관련 명령어를 내릴 수 있다.

docker0 와 eth0 의 연결: iptables -t nat

docker0 에서 외부 네트워크 연결을 위해서 특별한 프로그램을 별도 운영하진 않는다. 단지, NAT 를 위한 Iptables 를 세팅한다. 이것은 오래전에 리눅스 박스를 라우터 장비로 이용하기 위한 방법인(지금에 비교를 하자면 리눅스 박스를 공유기로 이용하는 방법이다.) 마스커레이드(MASQUERADE) 과 완전 동일하다.

docker0 가상네트워크를 공유기로서 동작하도록 설정하는 것이다. iptables 를 한번 봐보자.

패킷이 docker 컨테이너로 들어올때는 PREROUTING 을 거치고 외부로 나갈때는 POSTROUTING 을 거치게 된다.

만일 iptables 명령어로 rule 를 무효화 하게 되면 docker 컨테이너는 외부와 통신하는게 불가능해 진다.

Inter-Container Communication

Docker 의 네트워크는 기본적으로 Inter-Container Communication 이다. 여러개의 컨테이너를 생성하면 각 컨테이너사이에 통신이 가능하다.

만일 이기능을 끄고 싶다면 docker 를 기동할 때에 다음과 같이 옵션을 주면 된다.

혹은 daemon.json 파일을 다음과 같이 작성해서 서비스를 재시작하는 방법도 있다.

이렇게 한 후에 컨테이너 사이에 통신은 불가능해 진다. 이것을 도커 컨테이너 네트워크 격리(Docker Container Network Isolation) 라고해서 구글 검색을 하면 꽤 많은 내용이 나온다.

왜 도커의 네트워크를 격리해야하는가? 이것을 잘 이용하면 네트워크 설계를 보다 보안성을 강화하면서 안전하게 설계할 수 있다. 이것은 마치 AWS 에서 VPC 설계시에 라우터를 조작해 네트워크를 구성하는것과 흡사하다.

이런것을 보면 Docker 는 단순한 컨테이너로서의 기능만을 위한게 아니라는 것을 알 수 있다. 네트워크 레이어 설계도 Docker 를 이해하는데 매우 중요한 요소다.

docker0 브릿지 네트워크 ip 변경

구글을 검색하면 많은 글들이 존재하는데, 최신의 docker 에서는 그렇게 많은 노력을 기울이지 않아도 docker0 브릿지 네트워크의 기본 ip 를 변경할 수 있다.

docker0 브릿지의 기본 네트워크 ip 정보를 변경하는 것은 서브넷, 게이트웨이등을 함께 변경하는 것을 뜻한다. 이는 /etc/docker/daemon.json 파일에서 bind ip 를 지정함으로써 쉽게 바꿀 수 있다.

이렇게 변경하고자하는 아이피를 지정하고 docker 를 다시 시작하면 된다. docker 를 재시작해야하는 일이기 때문에 많은 컨테이너가 운영중일때에 하기에는 문제가 있다.

따라서 이런경우에는 default 브릿지인 docker0 를 애써 변경하기 보다는 또다른 브릿지를 하나 생성하고 이것을 각각 컨테이너에 붙이는 방법으로 변경하는 것이 좋다.

사용자가 정의한 브릿지를 생성하는것을 사용자 정의 네트워크(User-Defined Network) 라고 한다.

systemctl tomcat no bind 8005 port

Tomcat 을 설치하고 난후에 systemd 에 유닛으로 등록하고 나고 서비스를 시작하고 shutdown 을 하려고 할때에 다음과 같은 오류를 만날 수 있다.

8005 포트로 접속을 할 수 없어서 셧다운시에 오류를 발생시키는 것이다. 왜 이런문제가 발생할까? systemd tomcat 유닛의 내용은 다음과 같다.

그리고 이 상태로 다음과 같이 tomcat 을 서비스로 시작 한다.

이렇게 하고 난후에 netstat 명령어로 포트 리스닝 상태를 살펴보면 8005 포트가 보이지 않는다. 더 큰 문제는 shutdown 포트가 올라오지 않으면 Tomcat 이 작동하지 않는데 있다.

해결 방법은 의외로 간단하다. 다음과 같이 systemd tomcat 유닛 파일에 WorkingDirectory 를 CATALINA_BASE 로 해주면 된다.

이렇게 하게되면 tomcat 이 shutdown 포트까지 올라오면서 정상적으로 다 구동되게 된다.

ps, 이걸 몰라 3시간을 해멧다.

Ubuntu APT Could not get lock /var/lib/dpkg/lock 문제

우분투(Ubuntu) 를 부팅하고 난 후에 로그인을 하면 몇개의 새로운 업데이트가 있는지를 알려준다. 그래서 새로운 패키지 설치를 위해서 ‘apt upgrade’ 명령을 하게 되면 다음과 같은 오류 메시지를 만나곤 한다.

패키지를 설치하는 명령어인 dpkg 명령어가 이미 실행중인 것으로 인해서 실행이 안된다는 것이다. 실행을 할때에 lock 파일을 생성하게 되는데, 이를 근거로 혹시 다른 것이 이미 실행되고 있는건 아닌지 추측하고 있다.

도대체 무슨 일이 벌어지고 있는 걸까? 다른 것이 이미 실행중일지도 모르니까 다음과 같이 프로세스를 체크해 본다.

보아하니 apt.systemd.daily 이것이 apt 명령어를 실행하고 그래서 dpkg 가 이미 실행되고 있는 것으로 보인다.

이것은 아마도 부팅과 동시에 패키지를 업데이트 해주는일을 하는 녀석인 것으로 보이는데, 자동으로 패키지를 업데이트를 해준다니 얼마나 고맙겠냐만은 때로는 어떤 것이 설치되는지를 직접 선택하거나 해야하는 경우에는 자동으로 알아서 해주는것이 큰 위험이 될 수도 있다.

이것을 멈추게 하는 방법이 있다.

이렇게하면 부팅하면서 자동으로 apt 업데이트를 하는 건 막을 수 있다.

참고,

만일 부팅과장에서 각 서비스별 소비된 시간을 알고 싶다면 다음과 같이 확인해 볼 수 있다.

이렇게 보면 userspace 로 인한 시간이 1분이 넘어간다. 좀 더 자세하게 보기 위해서는 다음과 같이 확인해 볼수 있다.

Ubuntu18.04 호스트네임 영구 변경 설정

Ubuntu18.04 에서 호스트네임을 변경하기 위해서는 다음과 같이 해준다.

이렇게 한 후에 리부팅을 하면 원래 변경전 호스트네임이 나온다. 이럴때 /etc/cloud/cloud.cfg 파일에서 다음과 같이 변경을 해주면 된다.

이렇게 바꾼후에 다음과 같이 로그인 서비스를 재시작 해준다.

UBUNTU 18.04 KVM 게스트에 콘솔 접속하기

KVM 가상화를 사용하고 있고 게스트로 Ubuntu18.04 를 사용하고 있다면 콘솔 접속을 위해서는 다음과 같이 해주어야 한다.

/etc/default/grub 편집

grub 에서 ttyS0 에 콘솔 접속이 되도록 다음과 같이 편집해 준다.

위와같이 편집을 한 후에 grub 을 다시 작성해준다.

위와같이 설정을 하고 재부팅을 한 후에 KVM 콘솔 접속을 하면 아주 잘 된다.