Category: DevOps

DevOps

Gitlab, CI/CD 변수가 사용되지 않을때

Gitlab 에서 Settings -> CI/CD -> Variables 에서 CI/CD 에서 사용가능한 변수를 지정할 수 있다. 여기서 지정한 변수는 CI/CD 에서 활용되며 CI/CD 진행할때 운영체제의 환경변수로 자동 지정된다. 따라서 빌드시에 운영체제에 환경변수를 활용하고자 한다면 여기서 변수를 설정하면 된다.

AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 등은 운영체제 환경변수로 지정하면 AWS API 통신이 가능해진다. 소스코드에 하드코딩하는 것보다야 낫다.

Merge Request Pipeline 에서 변수가 활용 불가 문제

그런데, Merge Request Pipeline 에서는 이 변수가 적용되지 않았다. TF_USERNAME 이 적용되어야 하는데, 적용되지 않았다.

이는 CI/CD 변수의 Protect 기능 때문이다. 위에 스크린샷을 보면 변수 아래에 Protected 라고 적혀 있다. Gitlab 문서에는 다음과 같이 기술 되어 있다.

Protect a CI/CD variable

You can configure a project, group, or instance CI/CD variable to be available only to pipelines that run on protected branches or protected tags.

Merged results pipelines, which run on a temporary merge commit, not a branch or tag, do not have access to these variables.
Merge request pipelines, which do not use a temporary merge commit, can access these variables if the branch is a protected branch.

이런 제약을 없애기 위해서는 Protect 를 해제 하면 되는데, 변수 설정에서 체크 박스를 해제하면 된다. 기본값은 체크박스 체크된 상태이다.

“Protect variabe” 체크를 해제해주면 된다. 이렇게 되면 protected branches, protected tags 가 아니여도 변수가 적용된다.

Gitlab, Docker 빌드시 x509: certificate signed by unknown authority 오류 해결

Gitlab 은 CI/CD 를 내장하고 있다. 이는 Gitlab-runner 를 통해서 이루어진다. gitlab-ci.yaml 파일을 이용해 CI/CD 명세를 작성하면 Gitlab-Runner 가 이 파일을 읽어 실행해 준다. Gitlab-Runner 에는 타입이 존재하는데, docker 로 할 경우에 Docker 를 이용해서 CI/CD 를 진행하게 된다. 다시말해서, Docker 를 이용해서 Container 안에서 빌드, 테스트, 배포가 이루어진다는 것이다.

Private Certificate

문제는 사설 인증서다. Docker 컨테이너내에서 외부 접속을 하기 위해서 HTTPS 통신이 필요한데, 하필이면 HTTPS 가 사설 인증서를 사용한 것이라면 다음과 같은 오류가 발생한다.

Docker 컨테이너 안이라 사설 인증서에 대한 인증서를 붙여놔야 하는데, 어떻게 해야하는 문제가 있다.

Self-signed certificates or custom Certification Authorities

다음의 Gitlab 문서에 이에 대한 내용이 나와 있다.

Self-signed certificates or custom Certification Authorities

문서가 조금 부족한 감이 있는데, 두가지 절차가 필요하다.

Gitlab-Runner 에 볼륨 마운트

Pipeline 에서 사용할 Gitlab-Runner 에서, 당연히 Docker 타입, 볼륨 마운트 설정을 해준다. 이 설정은 Docker 명령어의 -v 옵션과 동일하다. 볼륨 마운트를 할때에 ca.crt (Root CA 인증서) 파일을 마운트 해준다.

Pipeline 이 실행되고 Docker 컨테이너가 시작되면 설정한 볼륨을 마운트 해준다. 그러면 Docker 컨테이너 내에 /tmp/ca.crt 파일이 존재하게 된다.

이제 Docker 컨테이너에 ca.crt 파일을 설치해주면 된다.

gitlab-ci.yaml 에 job 내에 ca.crt 설치

이제 gitlab-ci.yaml 파일에 job 내에 ca.crt 를 설치해 준다. 다음과 같다.

위 내용은 Alpine 이미지를 사용할 경우, ca.crt 파일을 설치하는 방법을 기술한 것이다. 아래 두번째에 보면 Gitlab-Runner 설정에서 마운트 되었던, /tmp/ca.crt 파일을 Alpine 이 CA 설정 디렉토리로 복사해주고 있다.

이렇게 하면 build 단계에서 인증서를 설치하게 된다.

결론

Gitlab-Runner 를 사용하다보면 대부분 Docker 기반으로 빌드,테스트,배포를 하게 된다. Shell 타입도 Docker 기반일 경우에 별도의 프로그램 설치와 설정이 필요 없기 때문이다. 하지만 사설 인증서를 사용할 경우에 통신이 되지 않을 수도 있는데, 위와 같은 방법으로 해결 할 수 있다.

Git 브랜치 목록 동기화

Git 를 사용할때에 원격과 로컬의 브랜치를 동기화되서 동작한다. 그런데, 원격 브랜치를 삭제하고 난후에 로컬 브랜치를 보면 동기화 되지 않는다.

위 예제를 보면 원격 브랜치가 여러개 보인다. 하지만 실제 원격 브랜치를 보면 main 빼고는 전부 삭제된 상태 이다. 이럴때는 다음과 같이 하면 된다.

위와같이 로컬에 원격 브랜치 목록이 실제 원격 브랜치 목록과 동기화 되었다.

GitLab, Merge Request 일때만 Auto DevOps 되도록 하기

Gitlab 은 매우 강력한 툴이다. 이거 하나면 다 된다. 문제는 다루기가 여간 쉽지가 않다는데 있다. 많은 것을 알고 있는 상태라면 Gitlab 을 손댈 필요가 없지만 그것을 몰랐을 때에는 예기치 않은 반응과 결과를 보게 된다.

Gitlab 은 CI/CD Pipeline 을 지원하는데, 이에 대한 설정은 Auto DevOps 에서 하게 된다. 정확하게 말하면 CI/CD Pipeline 을 Auto DevOps 라고 부른다고 이해해도 된다. 각 프로젝트 마다 Auto DevOps 설정이 존재한다. 이 설정의 기본은 다음과 같다.

“Default Auto DevOps pipeline” 이 체크되어 있는데, 아래 설명에 따라 별도의 CI 설정이 없을 경우에 Auto DevOps 를 실행한다는 의미다. 이 말은 저장소에 .gitlab-ci.yaml 파일이 존재할 경우에 무조건 실행 된다는 것을 의미한다.

이렇게 되면 CI/CD 를 실행하는데 있어서 조건을 달 수가 없다. 그래서 많은 사람들이 별도의 메뉴로 존재하는 줄 알고 열심히 찾아보지만 그런거 없다. 그러다보니 Gitlab 을 사용하면서 당황하게 된다. “나는 main(혹은 master) 브랜치를 기반으로 배포를 하고 싶은데, Gitlab 은 그냥 아무 브랜치에 push 만 되면 그냥 실행 된다… 별로 안좋네..” 이런 식으로 결론이 난다.

workflow

Gitlab 은 Auto DevOps (혹은 CI/CD) 관련해서는 .gitlab-ci.yaml 파일에서 모두 처리할 수 있도록 했다. 특정 조건에 맞게 실행되도록 workflow 라는 문법을 지원 한다. 예를들면 다음과 같다.

위 예제는 merge request 가 발생하거나 기본 브랜치에 push 가 발생하면 동작하도록 규칙(rule)를 정의한다. 위 예제 내용을 .gitlab-ci.yaml 맨 위에 적어놓게 되면 된다.

아니면 다음과 같은 예제도 있다.

commit branch 가 main (main 은 Gitlab 의 기본 브랜치) 도 아니고 파이프라인 소스가 merge request 도 아니면 CI/CD 를 실행하지 말라는 예제다.

rules

여기서 한가지 짚고 넘어가면, rules 다. rules 는 반드시 workflow 에서만 사용되는게 아니다. 각 stage 마다 사용 될 수 있다. 다음의 예제입니다.

terraform 를 위한 gitlab-ci 예제 중 일부 입니다. stage 단계에서 rules 를 설정해서 사용하고 있다는 것을 알 수 있습니다.

Gitlab 으로 terraform 상태(state) 관리하기

Terraform 을 여러명이 사용할때에 필요한 것이 Terraform 의 상태를 변경하지 못하도록 하는 것이다. terraform 을 실행할때마다 상태(state) 파일이 갱신되는데, 여러사람이 같이 일을 할때에는 이 파일을 공유해서 사용해야 한다.

대부분이 terraform state 파일을 AWS S3 저장소와 Dynamo DB 를 이용해 lock 을 거는 방식이 많이 거론된다. 이 방법은 AWS 클라우드를 사용해야 한다는 강제가 필요한데, 물론 Terraform 이 클라우드를 빠르게 코드로 만들도록 도와주기 때문에 어짜피 AWS 클라우드 인프라를 구성할 거면 S3 를 사용하는 것이 문제가 되지 않는다.

또, 인터넷상에 보면 Gitlab 을 이용한 상태관리 관련한 문서, 심지여 Gitlab 의 공식문서조차도 잘못된 내용이 있어 이 글을 작성한다.

하지만 꼭 AWS S3와 DynamoDB 를 이용해야만 가능하냐 하는 질문에는 그렇지 않다는 답이 존재한다. 이 문서는 AWS 클라우드 서비스를 이용하지 않고 Gitlab 을 이용해 Terraform 의 상태(state) 파일을 관리하는 방법에 대해서 알아 본다.

GitLab

매우 훌륭한 시스템이다. 소스코드 저장소는 물론이고 Container Registry, Terraform state 저장소, CI/CD, Wiki, Ticket 시스템등 거의 모든 IT 업무를 한곳에서 수행할 수 있게 해준다.

Terraform state 파일 저장소를 네이티브 기능으로 사용할 수 있도록 만들어져 있어서 이걸 이용하면 클라우드 저장소의 도움 없이도 Terraform 의 상태 파일을 관리 할 수 있다.

저장소 생성하기

Terraform 상태 파일 저장을 위한 저장소를 만들어 준다.

Terraform 상태 파일을 저장하기 위한 저장소 생성

Gitlab 에서 저장소 생성은 단순한 절차임으로 큰 어려움 없이 생성이 된다.

Terraform 파일 작성

간단하게 Terraform 파일을 작성해 보자. provider 와 backend, 그리고 AWS Resource 중에 Security Group 하나를 만들어 보자. 파일은 main.tf 와 backend.tf 두개로 작성 됐다.

main.tf

backend.tf

위 코드를 보면 변수 3개가 보인다. $PROJECT_ID 는 Gitlab 에 프로젝트 Settings -> General 을 보면 번호가 부여된 Project ID 를 알 수 있다.

API 통신을 위해서 인증 토큰이 필요하다. 공식문서에는 사용자 계정 토큰을 발행하라고 되어 있다. 사용자 계정 토큰은 사용자 Profile -> Access Tokens 에서 생성이 가능하다.

하지만, 여기서 한가지 주의해야 할게 있다. 인터넷을 검색해보면 개인 토큰으로는 인증 실패가 발생한다고 하는데, API 통신을 위해서는 Maintainer 권한을 필요로 한다. 그러니까 계정의 권한이 Maintainer 를 가지고 있지 않는다면 토큰을 발행이 되어도 인증에 실패하게 된다.

Gitlab 에서 API 통신을 위해서는 적절한 권한을 필요로하게 되는데, Maintainer 권한이 필요하게 된다. 이 말은 Access Tokens 은 Maintainer 권한만 있다면 사용자 구분 없이 사용이 가능하게 된다.

그러면, 프로젝트 Access Tokens 을 이용할 수 있지 않을까? 당연히 가능 하다. 앞서 생성한 프로젝트 -> Settings -> Access tokens 에서 토큰 발생이 가능하다. 프로젝트 토큰 발생은 사용자도 함게 생성되는데, 그 사용자는 bot 이다.

한가지 주의해야 할 것은 프로젝트 access token 을 생성할때에 권한(role) 을 Maintainer 권한으로 해야 한다. 그리고 이렇게 생성을 하게 되면 bot 계정이 생성이 되는데, 이 계정이 access token 소유자가 된다.

이 계정의 Id 는 @ 로 시작하는 문자열이다.

어떤 Access Tokens 을 사용해도 상관은 없다. 핵심은 권한(Role) 이다. 반드시 Maintainer 권한이 있어야 한다.

Terraform init

이제 Terraform 을 초기화 한. 초기화는 다음과 같은 명령어를 사용 한다.

TF_USERNAME 은 Project Access Token 소유자인 bot 이고 TF_PASSWORD 는 Project Access Token 이다.

terraform plan

이 명령어를 실행하면 드디어 Gitlab 저장소에 Terraform state 에 상태 파일이 생성된다. Operate -> Terraform states 에서 확인이 가능하다.

결론

인터넷을 살펴보면 Gitlab 을 이용한 Terraform state 관련 내용에서 Personal Access Token 으로 되지 않는다는 내용이 많다. 핵심은 Access Token 의 권한이다. 반드시 Maintainer 권한이 있어야 하며 이 권한만 있다면 Personal 이던 Project 이던 상관이 없다.

GitLab-Runner 설치

이 문서는 GitLab-Runner 설치 에 대한 것이다. GitLab 은 CI/CD 를 위해 외부 프로그램을 사용하는데, 이것이 바로 GitLab-Runner 이다. 외부 프로그램을 사용하기 때문에 반드시 GitLab 과 함께 있어야 하는것도 아니고 독립적으로 다양한 플랫폼에 설치해도 된다.

설치

설치는 아주 간단하다. 각 배포판, 플랫폼마다 패키지를 제공한다. 나는 Ubuntu 20.04 에 그것도 GitLab 서버에 설치할 예정이다. 다른 서버에 설치를 해도 되지만 테스트 삼아 설치하는 것이여서 이렇게 진행했다.

이렇게 설치를 하고 나면 /home/gitlab-runner 계정이 생성되며 systemd 에 gitlab-runner 서비스가 등록이되며 자동으로 실행이 된다.

우선 gitlab-runner 서비스를 중지를 해준다.

Gitlab 에 등록하기

GitLab-Runner 를 설치했다면 이제 이것을 GitLab 에 등록을 해줘야 한다. 이를 위해서 GitLab 에서 Runner 메뉴를 보고 URL 과 Token 값을 확인 한다.

gitlab-runner 셋업 정보

오른쪽에 보면 URL 과 token 값이 보인다. Gitlab-Runner 를 GitLab 서버에 등록을 해줘야 한다.

등록할때에 URL, Token 값을 입력해 준다. 그리고 무엇보다 중요한 executor 를 선택해줘야 한다. 나의 경우에 Java 컴파일을 해줘야 하기 때문에 executor 를 shell 로 선택해줬다. 이렇게 설정된 내용은 /etc/gitlab-runner/config.toml 파일에 기록된다.

정상적으로 완료됐다면 서비스를 시작해 준다. 그리고 GitLab 에서 다음과 같이 runner 가 보인다.

등록된 gitlab-runner

여기서 중요한 것이, config.toml 파일을 수동으로 조작한다고 해서 GitLab 서버에 등록이 되지 않는다. 반드시 register 를 이용해야만 등록이 가능하다.

Java 컴파일 환경 구축.

번외로 Java 컴파일 환경을 구축해 보겠다. gitlab-runner 의 프로세스를 보면 다음과 같다.

위 내용을 보면 working-directory 가 /home/gitlab-runner 이고 사용자가 gitlab-runner 이다. 따라서 /home/gitlab-runner 홈 디렉토리를 기반으로 runner 가 작동된다.

Java 컴파일 환경을 위해 다음의 필요하다.

  • java 1.8 컴파일러
  • maven

이 두가지를 gitlab-runner 계정에 설정을 해줘야 한다.

java 1.8 설정

java 1.8 은 Oracle JDK 가 아닌 오픈 소스인 Zulu JDK 를 사용하기로 했다. 현 시점에서 최신판을 다운로드 한다.

gitlab-runner 를 executor 로 작동하도록 했기 때문에 gitlab-runner 의 기본 쉘인 bash 를 기반이다. gitlab-runner 계정에 .bashrc 파일에 java 1.8 환경 변수를 등록해준다. gitlab-runner 는 서비스에 등록되어 동작은 root 계정으로 동작한다. 하지만 gitlab-runner 가 실행될때에 su 명령어로 gitlab-runner 계정으로 전환된다.

문제는 이때에 .bashrc 를 읽어들이지 않는다. 대신에 .profile 을 읽어들이게 된다. 따라서 각종 환경 변수들은 .profile 에 작성해야 한다.

maven 설치

maven 을 설치해준다.

이제 maven 을 위한 환경 변수를 등록해준다. 역시 .bashrc 파일에 해준다.

그리고 maven 에 setting.xml 파일을 수정해 의존성 패키지들의 저장소를 다음과 같이 바꿔 준다.

이로써 java 컴파일을 위한 gitlab-runner 설정을 완료됐다.

.gitlab-ci.yml 파일

Spring5MVC 프로젝트를 maven 으로 작성했다. Eclipse 를 쓴다면 간단하게 Spring5MVC 를 Maven 프로젝트로 손쉽게 제작할 수 있다. 이런 경우에 .gitlab-ci.yml 파일을 다음과 같이 간단하게 작성할 수 있다.

tags 는 gitlab-runner 에서 지정한 tag 를 말한다. gitlab-ci.yml 에서 gitlab-runner 를 구분하는 방법은 바로 tag 다. 이것은 GitLab 에서 gitlab-runner 를 수정하면서 함께 변경이 가능하다.

only 는 git 브랜치중에서 master 브랜치에 커밋이 발생했을때에 이를 실행하도록 한 것이다. git 는 전략적으로 브랜치를 자주 사용하는데, 전략에 따라서 특정 브랜치에 대해서만 작동하도록 할 수도 있다.

위 파일은 Deploy 는 없어서 단순하게 컴파일하는 것으로 끝난다. 나중에 Deploy 에 대해서 이야기 해보도록 하겠다.

GitLab 설치와 설정

GitLab 설치 하기. GitLab 은 무료로 사용가능한 git 저장소, ticket 시스템이다. github 의 오픈소스 버전으로 생각할 수 있지만 그것보다 많은 기능을 제공한다. 이 글에서는 gitlab 을 Ubuntu 20.04 LTS 에 설치와 설정에 대해서 알아보도록 하겠다.

준비

Gitlab 을 설치하기 전에 필요한 의존성 패키지들을 먼저 설치해 준다.

메일을 사용할 경우에는 메일 서버를 설치해줘야 하지만 여기서는 제외한다.

Gitlab 설치를 위한 저장소 추가

gitlab 홈페이지에서는 각 리눅스 배포판에 맞춰 스크립트를 제공한다. Ubuntu 20.04 를 위해 제공해주는 스크립트를 실행해 준다.

Gitlab 설치

접속을 위한 도메인을 결정해야 한다. 그리고 gitlab 은 SSL 접속을 권장하지만, 꼭 필요한 것은 아니다. 설치를 할 시점에서 도메인을 정할 수 있다.

별문제가 없다면 설치가 정상적으로 진행이 된다.

Gitlab 설정

Gitlab 설정은 ‘/etc/gitlab/gitlab.rb’ 파일을 이용 한다. 여기서 뭔가 변경을 하면 다음과 같이 재설정을 해야 한다.

접속 URL 바꾸기

접속 URL 은 설치시에 지정해 줬지만 나중에 바꿀 수 있다. gitlab.rb 파일을 열어 다음의 내용을 확인하고 바꾸면 된다.

Grafana 비활성화

Gitlab 서버를 모니터링을 하기 위해서 Grafana 를 내장하고 있다. 이것을 비활성화를 하고 싶다면 다음과 같이 비활성화를 해준다.

Prometheus 모니터링 비활성화

Prometheus 는 서비스에 대한 모니터링을 수집해주는 프로그램이며 Time Series 데이터베이스다. Grafana 는 이 데이터베이스를 읽어서 그래프를 그려주는 것이다.

Prometheus 뿐만 아니라 서비스의 각 메트릭을 수집해주는 Exporter 들이 있는데, Gitlab 에서는 prometheus_monitoring 을 비활성화하면 모든 Exporter 들도 비활성화가 된다.

이렇게 한 후에 gitlab 을 reconfigure, restart 를 한 후에 gitlab 상태를 보면 다음과 같다.

모니터링을 위한 export, prometheus 등의 프로세스가 없다.

업로드 용량 변경

Gitlab 은 nginx 를 웹서버로 사용한다. nginx 에서는 client_max_body_size 값으로 파일 업로드 용량을 결정하는데, 이것을 설정에서 바꾸면 된다.

데이터 저장 디렉토리 변경

만일 데이터 저장 디렉토리를 변경하고 싶다면 다음의 설정을 바꾸면 된다.

저장소를 “/opt/gitlab-data” 로 변경된다.

하지만, 만일 이미 저장소를 사용하고 있다면 다음과 같이 해줘야 한다.

자세한 것은 다음 링크를 참고한다.

소프트웨어 엔지니어링에서 파이프라인(Pipeline)은 무엇인가? Deployment, CI & CD 파이프라인에 대한 소개

이 글은 bmc blogs 의 “What is a Pipeline in Software Engineering? Intro to Deployment, CI, & CD Pipelines” 을 번역한 것 입니다. 원작자의 허락없이 재개시 및 상업적 이용은 불가합니다.

https://www.bmc.com/blogs/deployment-pipeline/

소프트웨어 엔지니어링 팀에서 파이프라인(pipeline)은 개발자나 DevOps 전문가가 효율적이면서도 확실하게 그들의 코드를 컴파일(Compile), 빌드(Build) 그리고 그들의 프로덕션 컴퓨팅 플랫폼에 배포(Deploy) 하게 해주는 자동화된 프로세스들의 묶음(set) 이다. 파이프라인이 이래야 한다거나 반드시 활용해야할 도구(Tools)를 지정하는 강하고 빠른 규칙은 없지만, 파이프라인이 가져야할 가장 일반적인 컴포넌트들이 있다. 빌드 자동화(build automation)/지속적 통합(continuous integration), 테스트 자동화(test automation), 그리고 배포 자동화(deployment automation) 이다.

일반적으로 파이프라인은 다음의 카테고리로 구분되는 일련의 도구들로 구성된다.

  • Source Control
  • Build tools
  • Containerisation
  • Configuration Management
  • Monitoring

소프트웨어 배송 파이프라인(Software Delivery Pipeline) 개념의 핵심은 어떤 파이프라인의 단계 사이에 수동적 단계나 수동적인 변경이 필요없는 자동화(automation) 이다. 휴먼에러(Human error)는 이러한 지루하고 반복적인 작업을(역, 파이프라인의 단계들을 말한다) 수동으로 하게되면 발생할 수 있고 결국 잘못된 배포로 인해 올바른 산출물 생성에 영향을 미치고 잠재적으로 SLA 까지 영향을 준다.

Deployment Pipeline

배포 파이프라인은 자동화된 방식으로 버전 컨트롤(Version control) 로부터 코드를 가지고 오고 당신의 애플리케이션 사용자에게 손쉽게 활용할 수 있도록 만들어주는 프로세스이다. 개발팀이 프로젝트나 기능에 대해 일을 할때에 그들의 일을 빌드, 테스트, 배포를 위한 확실하고 효율적인 방법이 필요하다. 역사적으로, 이것은 많은 커뮤니케이션과 많은 휴먼 에러를 발생시키는 수동 프로세스들이였다.

전통적인 배포 파이프라인 단계는 다음과 같다.

Version Control

일반적으로 코드를 가지고 일을하는 소프트웨어 개발자들은 코드 변경사항을 소스 컨트롤에(e.g. github) 커밋 한다. 소스 컨트롤에 커밋하면 코드 컴파일화, 유니테스트, 코드 분석 그리고 인스톨러 생성을 트리거하는 배포 파이프라인의 첫번째 단계가 시작된다. 이런 모든 과정이 성공적으로 완료되면 실행결과물은 바이너리로 만들어지고 나중에 사용위해 아티팩트 저장소에 저장 된다.

Acceptance Tests

합격 테스팅은 비지니스에 의해서 미리 정의된 합격 기준에 부합하는 테스트를 위해 미리 컴파일/빌드된 코드에 대해 테스트 묶음을 실행하는 프로세스이다.

Independent Deployment

독립 배포는 컴파일되고 테스트된 아티팩트를 개발환경에 배포하는 프로세스다. 개발 환경은 이상적으로 프로덕트 환경의 판박이 복사본이여 하거나 최소한 아주 비슷해야 한다. 이것은 기능적으로 모든 추가적인 자동화되거나 수동 테스팅을 위한 인프라 준비와 같은 프로덕션에 대해 테스트되어질 수 있는 소프트웨어 이다.

Production Deployment

이 프로세스는 일반적으로 운영팀(Operations) 이나 데브옵스팀에 의해서 다루어진다. 이것은 독립 패포 프로세스와 매우 유사해야 하며 라이브 프로덕션 서버에 코드를 배포해야 한다. 전통적으로 이 프로세스는 예기치못한 이벤트 이슈에 쉽게 버전 롤백을 하거나 제로 다운타임 배포를 위해서 Blue/Green 배포 혹은 Canary 릴리즈를 포함 한다. 제로 다운 타임이 아닌 상황에서 배포 기능 릴리즈 윈도우는 일반적으로 비지니스와 협상을 했었다.

Continuous Integration and Continuous Delivery Pipelines

Continuous Integration (CI) 는 개발자들이 하루에 여러번 그들의 코드를 버전 제어 저장소에 체크하는 방법이다. 이러한 체크는 오류를 빠르고 쉽게 찾을 수 있게 해주며, 자동화된 빌드 파이프라인은 이러한 체크인으로부터 트리거 된다.

CI 의 장점은 다음과 같다.

  • 크기가 좀 더 작은 변경은 좀 더 큰 코드 베이스로 통합하기가 좀 더 쉽다.
  • 당신이 무슨 일을 하고 있는지를 다른 팀 멤버에게 보여주기가 좀 더 쉽다.
  • 좀 더 큰 작업 부분에 버그를 좀 더 적은 디버깅 작업으로 문제을 해결하기 아주 쉽도록 조기에 발견하게 한다.
  • 일관된 코드 컴파일/빌드 테스팅
  • 거의 없는 통합 이슈는 빠른 배포를 가능하게 한다.

Continuous Delivery (CD) 는 개발자와 운영엔지니어가 버그 수정, 기능 및 구성 변경 사항을 프로덕트에 안정적으로 신속하고 지속적으로 배포할 수 있도록 해주는 프로세스다. 지속적 배포는(Continuous Delivery) 필요시 자신있게 수행 할 수 있도록 반복적으로 수행되는 코드 배포 파이프라인의 이점을 제공한다.

CD의 이점은 다음과 같다.

  • 아주 낮은 리스크 릴리즈 – Blue/Green 배포와 카나리 릴리즈는 사용자가 신경쓰지 않아도 되는 제로 다운타임 배포를 보장하며 이전 릴리즈로 롤백하는데 상대적으로 어려움이 없다.
  • 빠른 버그 픽스 & 기능 배포 – 기능 또는 버그 수정을 완료하고 승인 및 통합 테스트를 통과한 경우 CI & CD 사용 – CD 파이프라인은 이것들을 재빨리 프로덕트에 배포한다.
  • 비용 절약 – 지속적인 배포를 통해 팀은 기능 및 버그 픽스를 작업 배치로 처리할 수 있으므로 사용자 피드백을 훨씬 빨리 받을 수 있다. This allows for changes to be made along the way thus reducing the overall time and cost of a project

Blue/Green Deployments

Blue/Green 배포 프로세스의 활용은 하나는 Blue, 다른 하나는 Green 으로 이름붙여진 프로덕트 환경 미러 복사본을 생성함으로써 리스크와 다운타임을 줄인다. 오직 하나의 환경만이 매시간 라이브 프로덕트 트래픽을 제공하도록 살아 있다. 배포 소프트웨어가 non-live 환경에 배포되는 중에는 – 이것은 라이브 프로덕트 트래픽이 배포되는 동안 영향을 받지 않는다는 것을 의미한다. 테스트는 현재 라이브 환경이 아닌 곳에서 실행되며, 모든 테스트가 사전에 정의된 기준을 충족하면 트래픽 라우팅이 라이브 환경이 되도록 라이브 환경이 아닌 환경으로 교체한다. 이 과정은 기존 라이브 환경이 현재 라이브 환경이 아닌것으로 되면서 다음번 배포에 반복된다.

Canary Deployments

Blue/Green 배포와는 달리, Canary 배포는 병렬로 운영되어지는 중복 환경에 의존하지 않는다. Canary 배포는 모든 사용자/서버들에 지속적으로 릴리즈를 롤 아웃(Roll out) 하기 전에 라이브 프로덕션 테스트를 위해 사용자/서버들의 백분율이나 특정 버전으로 릴리즈를 롤라웃 한다. Canary 릴리즈의 주요한 장점은 일찍 실패를 탐지할 수 있다는 것과 예외나 실퍠 이벤트 발생시에 영향을 받는 사용자/서버들의 수가 제한됨에 따라 일부 변경된 것만 롤백할 수 있다는 것이다.

요약을하면, CI 는 소프트웨어 개발팀이 그들의 코드를 체크인하고 품질을 확인하고 컴파일할 수 있도록 하는 자동화된 프로세스다. CD 는 개발과 운영 팀이 자동화된 방식으로 그들의 최종 기능에 새로운 기능과 버그 픽스를 안정적이고 효율적으로 배포할 수 있도록 해준다.

아래에 몇가지 CI/CD 파이프라인 빌드를 위해 사용할 수 있는 다양한 도구들이 있으며, 모두 무료로 시작할 수 있는 이점과함께 안정적이고 강력한 CI/CD 파이프라인을 빌드하는데 사용되어질 수 있다.

20 개의 Ansible 인터뷰 질문

이 글은 Arie Bregman 씨의 “20 Ansible Interview Questions” 을 번역한 것입니다.

질문1

Ansible 에서 다음 각각의 컴포넌트에 대해서 이들 사이의 관계를 포함해 설명하시오.

  • Task
  • Module
  • Play
  • Playbook
  • Role

Answer

이 질문은 당신이 Ansible 의 기본적인 컴포넌트에 익숙한지 않한지, 그들이 어떻게 상호작동 하는지를 체크한다. 나는 이것이 우리가 Ansible 로 하고자하는 모든 것에 기본인만큼 매우 중요한 것임을 알았다.

  • Task – 특정 Ansible 모듈(Module) 호출하기
  • Module – 여러분의 호스트나 원격 호스트에서 Ansible 에 의해서 실제 실행되어지는 코드의 묶음. 모듈들은 카테고리로(database, file, network, …) 인덱스되고 task 플러그인처럼 첨조된다.
  • Play – 주어진 호스트에 실행되어질 하나 혹은 그 이상의 Task 들.
  • Playbook – 하나 혹은 그 이상의 Play들. 각각의 Play 들은 같은 호스트 혹은 다른 호스트들에서 실행되어질 수 있다.
  • Role – Ansible Role 은 어떤 기능이나 서비스를 기반으로 자원들을 그룹화 해 쉽게 재사용할 수 있도록 해준다. Role 에서 variables, defaults, files, templates, handlers, tasks 그리고 metadata 를 위한 디렉토리를 가진다. 그리고 Role 을 Playbook 에 지정해서 사용할 수 있다.

더 자세한 Ansible core components 사항은 여기서 확인할 수 있다.

질문2

‘/tmp/new_directory’ 디렉토리를 생성하는 task 를 작성하라.

Answer

매우 기본적인 질문지만 당신이 Ansible 을 어떻게 활용하는지를 알수있게 해준다. 많은 사람들이 Shell 이나 Command 모듈을 사용하는 것으로 이 질문에 답합니다. 이것이 꼭 나쁜것은 아니지만, 제일 좋은 사례는 항상 명시적인 Ansible 모듈을 사용하는 것 입니다. (이 경우에, file 모듈을 사용하는 것이다.)

왜 그런가? 주요한 이유는 가독성(readability) 때문이다. 어떤 액션들은 서로 다른 운영체제에 따라 다르게 실행되지만, Module 은 언제나 같은 것을 사용하고(운영체제에 관계 없이) 어떤 Ansible 사용자라고 할지라도 Task 를 읽다보면 그것이 무엇을 뜻하는지를 알게된다. (특히 긴 쉘 명령어일 경우)

주의: 이것은 Module 이 ‘shell’ 이나 ‘command’ 로 지정한 명령어보다 반드시 좀 더 빠르다는 것을 의미하지 않는다.

디렉토리 생성 Task 는 다음과 같다. 

질문3

다음 Play 결과는 무엇인가?

Answer

작성된 코드가 주어지면 항상 철저히 검토하세요. 만약 여러분의 대답이 “이것은 실폐할 것이다” 라면 맞습니다. 이 코드는 실행한 호스트로부터 수집된 정보의 일부인 ansible_hostname 이라는 Fact를 사용하고 있다. 하지만 이 경우에, Fact 수집을 비활성화(gather_facts: no) 했기 때문에 ansible_hostname 변수는 정의되지 않을 것이며 따라서 결과는 실폐하게 된다.

이 질문의 목적은 Fact 가 무엇인지를 체크하기 위한 것이지만 여러분이 아주 세세한 부분까지 신경을 쓰고 있는지를 체크하는 것이기도 하다.

유사하게 다음과 같은 질문이 있을 수 있다.

  • 활용가능한 모든 Fact 를 나열하는 방법은?
  • 당신만의 Fact 를 지정하는 방법은?

질문4

시스템에 ‘/tmp/mario’ 파일이 존재한다면 모든 시스템에 ‘vim’, ‘zlib’ 설치를 위한 Playbook 을 작성해라.

Answer

이 질문에 답하기 위해서 여러분은 register, conditionals 그리고 loops 에 익숙해져 있어야 한다.

첫번째 Task 는 ‘stat’ 모듈을 사용해서 각 시스템에 파일이 존재하는 체크한 결과를 ‘register’ 를 사용해서 ‘mario_f’ 변수에 담아두는 것이다. 이렇게 하면 등록한 변수를 어떤 다른 Task 에서도 사용할 수 있다. 이 경우에, 우리는 ‘/tmp/mario’ 파일의 상태를 담았고 다음 Task 에서 만약 파일이 존재한다면 패키지들을 설치하게 된다.

여러분이 본것처럼, 패키지들을 설치하기 위해서 우리는 리스트(list)를 반복할 수 있게해주는 “with_items” 루프를 사용했고 리스트에 아이템마다 module/task 를 실행했다. loop는, 다른 프로그래밍 언어처럼, Ansible 의 기본적인 사항이고 여러분은 Ansible 이 지원하는 다른 타입의 loop 을 알고 있어야 한다.

다른 주목해야할 라인은 ‘become: yes’ 인데, 이것은 Task 를 root 처럼 실행하게 해주기도 하지만 다른 사용자로 실행되도록 사용자를 지정해줄 수 있다(e.g. become: ‘toad’). 패키지 설치는 시스템의 sudo 권한만으로 수행할 수 있기 때문에 이 라인이(become: yes) 이 포함되어 있지 않으면 패키지 리스트 설치 Task 는 실패할 것이다.

다른 주목해야할 라인은 ‘become: yes’ 인데, 이것은 Task 를 root 처럼 실행하게 해주기도 하지만 다른 사용자로 실행되도록 사용자를 지정해줄 수 있다(e.g. become: ‘toad’). 패키지 설치는 시스템의 sudo 권한만으로 수행할 수 있기 때문에 이 라인이(become: yes) 이 포함되어 있지 않으면 패키지 리스트 설치 Task 는 실패할 것이다.

*Bonus: 어떤 Ansible 모듈들은 인자로(argument) 리스트를 받을 수 있다. 이 질문에서, loop 처리는 ‘package’ 모듈에 package_list 변수를 직접 제공함으로써 완벽하게 제거할 수 있었다. 또, 우리는 Ansible 에 정규표현식으로 파일 리스트를 반복하는 ‘with_fileglob’ loop 를 사용함으로써 “stat” 모듈을 완벽하게 제거할 수 있다. 이를 종합하면 다음과 같다.

질문5

controller 그룹을 제외한 모든 서버에 다음의 내용을 가진 ‘/tmp/system_info’ 파일을 배포하는 Playbook 을 작성하라.

<HOSTNAME>과 <OS>는 실행되는 호스트의 실제 데이터로 바뀌어야 한다.

Answer

system_info 파일을 배포하는 Playbook 은 다음과 같다.

system_info.j2 템플릿 내용은 다음과 같다.

Template 사용은 여러분의 Playbook 이나 Role 들을 좀 더 다이나믹하게 해주고 다른 시나리오와 쉽게 적용할 수 있게 해준다. Ansible 은 파일의 동적 템플릿 구성을 위해서 ‘Jinja2(진자2)’ 불리는 강력한 템플릿 엔진을 사용한다. 많은 인기있는 프로젝트와 회사들이 이것을 사용중이고 우리는 시간을 갖지고 미래에 여러분이 그것을 잘 사용할 수 있도록 사용법을 익히는것을 강력히 추천 합니다.

Ansible 을 위한 Jinja 템플릿을 작성할때에 템플릿 최상단에 ‘ansible_managed’ 변수를 추가하는 것이 가장 좋은 사례 입니다. 이 변수는 Ansible 로 생성되거나 관리되는 출력파일을 누구나 읽을수 있는 문자열로 확장 됩니다. 그 다음, 우리는 호스트 이름을 위해서 ansible_hostname 을, OS 배포판을 위해서 ansible_distribution 을 사용했다.

이 질문은 다른 방법으로 구현 될 수 있다는 점에 유의해라. 예를들어, ansible_hostname 을 사용하는 대신 어떤분은 inventory_hostname 을 사용할 것이다. 그들은 같지 않지만, 이 경우에는 둘다 괜찮다.

질문6

어떻게 여러분의 Ansible 기반 프로젝트를 테스트 하는가?

Answer

몇몇 인터뷰때 이 질문을 했었는데, 아주 많은 다른 대답을 받았다. 그 답변들 중 몇가지 이다.

  • Manual run: “나는 그냥 그것을 실행시키고 시스템이 원하는 상태에 있는지를 체크한다” – 개인적으로 나는 이런 대답만 하는것을 싫어한다. 나는 이것이 가장 쉬운방법임에 동의하지만 잠재적으로 아주 위험하다. 비록 개발환경에서 새로 작성한 Role 을 테스트한다 할지라도, 이것이 프로덕트 환경에서 같은 결과를 얻는다는 것을 의미하지 않는다.
  • Check mode – yes, check mode 는 실제로 check mode 없이 실행할 경우 무슨일을 했는지 결과를 알려주므로 Ansible 코드를 테스트하기에 좋은 방법이다. 그래서 여러분은 Ansible이 실행되면 여러분이 기대한 행동이 나오는지를 쉽게 볼 수 있다. 하지만 여기서 “그리고 스크립트 어떤가?” 라는 질문이 있다. 보통, 나는 대답으로 “그게 뭔데?” 라는 소리를 들는데, 만일 롤(Roles)과 플레이북(Playbook) 에 스크립트를 사용하지 않는다면 괜찮겠지만, Check Mode 는 스크립나 명령어를 실행할 수 없다는 것을 알아야 한다. 그것을 실행하기 위해서는, “check_mode: no”를 사용하여 특정 Task에 대한 Check Mode 를 비활성화해야 한다.
  • Asserts – 나는 Python처럼 다른 언어를 테스트하는 방법과 비슷한 테스팅 메소드로 Assert 를 좋아하는데 중요한 것은 여러분의 시스템이 Check mode 와 같은 초안이 아닌 Task가 특정 자원을 원하는 상태로 변경했다는 실제 검증처럼 원하는 상태에 도달했는지 확인해준다.

요약하면, 단순하게 여러분이 선택을 설명해야할때 자신감을 가져라.(또, 누군가 이것들을 모두 사용하도록 기대하는 것은 현실적이지 않기 때문에 이 모두를 사용하지 마세요.

질문7

데이터베이스 그룹에(RedHat 으로 가정하고) 모든 서버에 PostgreSQL 설치하고 postgresql.conf.j2 템플릿으로 postgresql.conf 설정을 업데이트하는 Playbook 을 작성하시오.

추가로, 설정 업데이트 task만 실행하기 위해나 방법을 제시하라.(패키지 설치하지 않고..)

Answer

여기에는 놓치지 말아야할 두가지가 있다: handlers 와 tags. 여러분의 Playbook 은 다음과 비슷할 것이다.

보시는 봐와같이, 하나의 파일에 모든 것을 담았지만 더 좋은 해결법은 Roles 를 생성하게 하고 각 섹션들을 그들만의 디렉토리에(vars, handlers, tasks,…) 넣는 것이다. 나중에 Roles에 대한 상세한 질문과 답변을 하겠다.

첫째로 봐야할 것이 ‘Handler’다. Handler는 변화에 따른(보통 task) 트리거 액션을 수행한다. 위에서 본것처럼, 문법은 확실히 단순하다, ‘notify’ 키워드를 사용함으로서 실행을 위한 액션 리스트를 제공할 수 있다. 이것은 설치를 위해 필요한 메인 Task와 PostgreSQL 설정이 무엇인지, Task를 완료하는데 필요한 작은 “sub” 액션이 무엇인지를 명확하게 구분하게 해준다.

두번째로 봐야할 것은 ‘tags’다. 이것은 어떻게 설정 업데이트 부분만 실행하도록 하는지에 대한 질문의 두번째 부분에대한 답변이다. 여러분이 100 task를 가지고 있고 그들중에 아주 오직 작은부분만 실행되길 원있다고 가정하고 애플리케이션 업데이트를 담당하는 네가지 Task 를 가정해보자. tags 가 없다면, 여러분의 playbook 에서 모든것을 실행해야만하지만 tags를 사용하면 특정 tag 로 표시한 tag만 실행할 수 있다.

질문8

다른 값을 가진 여러 장소에서 같은 변수이름을(whoami) 사용한다고 생각해보자.

  • role defaults -> whom:mario
  • extra vars(-e 를 통해서 Ansible CLI 로 전달되는 변수들) -> whom:toad
  • host facts -> whoami:luigi
  • inventory variables(타입과 상관없다) -> whoami:browser

최종적으로 어느것을 사용해야 합니까? 왜?

Answer

정답은 ‘toad’ 다.

Variable precedence 는 변수들이 다른 위치에 있을때에 어떻게 변수들이 서로 오버라이드(override) 하는지에 대한 것이다. 만약 아직 여러분이 그것을 다루어보지 못했다면 어느시점에서 그것을 다룰것인데, 그것을 깨닫기에 유용한 주제다.

질문의 문맥에서, 순서는 extra vars(매번 모든 다른 변수를 오버라이드한다) -> host facts -> inventory variables -> role defaults (제일 약하다)

전체 목록은 위 링크에서 찾을 수 있다. 한가지 주의해야 할것은 Ansible 1.x 와 Ansible 2.x 는 아주 다르다.

질문9

여러분에게 Ansible 모범 사례로 친숙한 것 (적어도) 3가지는?

Answer

  • 여러 파라메터를 사용할때에 YAML dictionary 포맷을 사용하는 것이 더 낫다. 나는 개인적으로 좀 더 읽기 편하다.
  • “항상 태스크 이름을 사용하라”. 여러분이 ‘debug’ 모듈을 사용하는 것처럼 아주 단순한 것일지라도 매번 태스크를 추가할때마다 name 을 사용하는 것으로 얻을 수 있는 이득이 있다. task의 name은 왜 추가되었고 그것이 무엇을 하는지와 같은 어떤 정보를 제공한다. 알려진 버그를 해결할 수 있는 벙법일 수도 있고 길고 지루한 명령일 수도 있으므로 사용자가 playbook을 읽거나 사용할때에 간단하게 무엇을 하는지를 기술한다면 고마워할 것이다.
  • Ansible 코드의 모든 변경은 ansible-lint 로 전달되어야 한다. 이것은 기본적으로 best-practices checker 인 또 다른 비공식 모범 사례다. This is why I consider it as one of the most important best practices to implement as it makes it easier to make sure other best practices are being followed, especially in a shared repository where you have several contributors(역, 모범 사례가 되기 위해서는 task 의 name 을 사용하는 것이 좋다. 여러 컨튜리뷰터들과 저장소를 공유할때에는 이러한 것이 모범 사례가 되게 만드는데 도움을 준다.

이미 언급한 바와같이, 언급된 모든 모범 사례가 공식적인(Ansible 문서) 것이 아니며 여러분이 그것이 왜 모범 사례인지를 설명할 수 있다면(좀 더 정확하게 좋은 연습사례) 그것으로 괜찮다.

질문10

“The inventory file is in <inventory_file_path> and the inventory groups are <inventory_groups>” 내용을 가지는 ‘/tmp/info’ 파일을 모든 호스트에 생성하는 Ansible Ad-Hoc command 를 작성하라

주의: 인벤토리 그룹에 포함된 호스트도 나열해야 한다.

Answer

Ansible 을 실행하는 다른 방법을 아는 것은 시간을 절약해 준다. 그중에 하나가 Ad-Hoc 방법인데, 원격 호스트에 빠르게 무엇이든 실행해준다.

이 경우에, ad-hoc command 는 다음과 같을 것이다.

-m은 모듈 이름을 지정하기 위한 것이다. 우리는 ‘copy’를 사용하지만, 동일한 결과를 얻기 위해서 다른 모듈을 사용할 수도 있다.

-a파일의 내용과 어디에 생성할지를 모듈에 전달하기 위한 아규먼트다.

나는 이것에 친숙해지기 위해, 실전에서 사용할때 충분히 편안함을 느낄수 있도록 ad-hoc command를 여러번 실행해 볼것을 권장한다.

질문11

ansible-pull 은 무엇인가? 어떻게 ansible-playbook 과 다른가?

Answer

우리는 ansible-playbook 을 실행하는 것이 컨트롤 노드로 알려진 호스트에서(우리가 명령을 실행하고 있는 노드) 운영중인 호스트에 어떤 설정을 강제한다는 것을 알고 있다.

ansible-pull 또한 설정을 적용하지만 컨트롤 호스트로부타가 아닌 관리 호스트로부터 실행된다. 이것은 주어진 URL 저장소로부터 설정을 pulling 한다.

이것은 여러분이 접속한 호스트에서 중앙 위치로부터 설정을 강제하는 Reversed Architecture 가 필요할때에 유용할 수 있다.

질문12

여러분은 디렉토리 목록을 가지고 있고 첫째로 발견한 디렉토리를 원격 서버로 복사하는 Task를 작성하기 원한다.

Answer

역주: Ansible 2.7 에서는 없어진듯 보인다. 공식문서에서 검색했지만 나오지 않는다.

질문13

다이나믹 인벤토리는 무엇인가?

새로운 dynamic inventory 스크립트를 작성할 때 어떤 규칙을 따르는것이 중요한가?

Answer

라인을 추가/삭제하거나 수동으로 호스트이름 목록을 업데이트하는 default 혹은 static 인벤토리와 다르게, dynamic inventory 는 클라우드(Cloud)나 LDAP 과 같은 외부 소스로부터 정보를 추출함으로써 생성어된다. 대부분의 이러한 dynamic 저장소 스크립트는 contrib/inventory 디렉토리에서 찾을 수 있다.

새로운 동적 인벤토리를 개발할 때 ‘-list’인수를 사용하여 호출하면 해당 스크립트의 중요한 결과가 JSON 형식에 그룹을 출력한다. 다음과 같이 group:managed_hosts 처럼 할 수 있다.

혹은 다음과 같이 group:dict_of_variables 처럼 할 수 있다.

물론, 두개를 혼합할 수 있다.

dynamic inventory 에 대한 더 많은 정보는 여기서 찾을 수 있다.

질문14

파일의 전체 또는 상대 경로가(-e 와 함께 변수를 전달 함) 주어지면 다음을 수행하십시오.

  1. 현재 작업 디렉토리나 주어진 위치에서 찾아라.
  2. 만일 파일을 찾을 수 있다면, 리모트 호스트 사용자 홈 디렉토리에 그것을 복사하라. 만일 파일을 찾지 못할 경우, run/execution 은 실패로 처리하라.

Answer

질문15

Apache 설치를 위한 롤을 작성하라.

Answer

나는 이 질문이 인터뷰에서 아주 인기 있는 질문이라고 생각한다. 왜냐하면 ‘role’은 Ansible의 핵심 컴포넌트이며 이것은 앞에 질문에서 논의했던 tasks, templates 그리고 variables 와같은 많은 컴포넌트들을 사용하도록 만들기 때문이다.

이 질문에 대한 하나 이상의 답이 있다는 점에 주의해야 한다. 나는 짧지만 포괄적인 답을 제공할 것이다. role 에서 모든 디렉토리를 사용하는 자세한 대답은 아마도 추가 점수를 줄 것이다.

구조부터 시작하자.

이것은 매우 표준적인 구조지만 여러분은 각 디렉토리가 왜, 무엇을 위해 사용되고 이 케이스에서 Apache 설치를 어떻게 구현하는지 익숙해질 필요가 있다.

이것은 매우 표준적인 구조지만 여러분은 각 디렉토리가 왜, 무엇을 위해 사용되고 이 케이스에서 Apache 설치를 어떻게 구현하는지 익숙해질 필요가 있다.

vars 를 시작해보자. vars 는 우리가 role 에서 사용할 모든 변수를 가진다. 무엇이 변수일 수 있나? 만약 우리가 서로다른 운영체제에 이 role 을 사용할것이라면, apache2의 서비스 이름은 변수일 수 있다. Fedora에서, 서비스 이름은 httpd 일 것이지만 Debian 에서는 apache2 로 부른다. 또 다른 변수로 각 운영체제에 패키지를 설치해기 위해 정의한 apache2_packages 일 수도 있다. 어떻게 이것을 구현하는지 보자.

RedHat.yml 살펴보자.

Debian.yml 살펴보자.

이제 Handler 로 가보자. Handler 는 어떤 변화(Change)에 따라 트리거되는 액션이다. 이 경우, 아주 흔한 handler 로 ‘restart service’ 일 수 있다.

이 handler 는 설정에 변경이 있은 후에 apache2 시작을 위해서 사용되어질 수 있다. {{ apache2_service }} 는 RedHat.yml 과 Debian.yml 에 정의되어 있음을 기억해라.

다음으로, 우리는 defaults/main.yml 에서 기본 변수들을 정의할 것이다.

만약 defaults 와 vars 차이에 의문이 든다면 여러분은 default를 모든 타입의 운영체제나 시나리오에 사용하기 위한 공통변수로 생각해야 한다. 반면에, vars 는 특별한 환경/케이스에 사용하기 위해 수정된 변수들이다. 이 경우 운영체제 타입이다.

meta folder 는 role 에서 별도의 행동을 정의하기 위한 장소처럼 행동한다. 일반적으로 대부분 role 의존성을 정의하는데 사용한다. 이것은 role 이 다른 role 에 의존성이 있는 경우인데, 예를들어 자바(Java) 기반 애플리케이션 설치하는데 설치된 자바가 필요한 것이다. 이 예제를 만들어보면 우리는 두개의 role 을 가질것이다.

  1. Java 설치 role
  2. Elasticsearch 설치 role

우리의 play 는 다음과 같을 것이다.

하지만 우리는 다른 사람과 role들을 공유하는 걸 좋아하기 때문에, ElasticSearch role을 사용하고자하는 유저는 ‘Java’ 라는 다른 role 을 의존성을 모를 수 있다. 따라서 meta folder에 다음과 같이 라인을 추가해줘야 한다.

이것은 ‘elasticsearch’ role 을 불러오기 전에 ‘java’ role 을 시도하고 실행할 것이다. 이것은 이전의 play 를 재작성하도록 해준다.

최종적으로, 우리는 몇개의 task들을 정의할 것이다. role의 핵심은, 무엇을 실행시킬 것인지를 정의하는 부분이다. 우리는 목적에 기반한 추가적인 task 를 포함하는 단순한 메인 파일을 가질 것이고 OS 타입에 따라서 그것이 동작할 것이다. 올바른 패키지를 설치하기 위해서, 우리는 각 OS에마다 사용할 이전에 정의했던 변수들을 포함할 것이다.

이제, install-RedHat.yml을 살펴보자.

최종적으로, 이것이 앞에 모든 파일들을 생성한 이후 구조다.

기억해라, 이것은 완전한 해결책이 아니며 당신이 더 장황하고 상세한 답변을 줄수록, 당신은 더 많은 신뢰를 얻을 것이다.예를들어, 설정을 위해 템플릿을 가지는 템플릿 디렉토리을 추가하거나 Apache 설정 Task 추가등이다.

질문16

여러분은 다음의 play 를 가진다.

그리고 여러분은 다음의 command 를 실행한다.

test 변수의 출력값은 무엇인가?

  • test 1 2 3
  • test
  • empty string
  • the variable is not defined

Answer

대답은 ‘test’다.

이것은 속임수이고 여러분이 shell 과 Ansible을 이해하고 있는지를 체크한다. 이 경우에, command는 shell에 의해서 우선 처리 때문에, 인용문의 내용과 백슬래쉬와 빈공백 이후의 모든것은 무시된다.

면접관으로서, 여러분은 대부분의 면접자들이 이것에 올바른 대답을 못것인지 아니면 단순한 추측은 아닌지 알아야 하며 이것이 Ansible에 익숙한지 아닌지를 나타내는 지표는 아니다.

해결책은 전체적으로 ‘-e’ 이후에 내용을 인용하는 것이다.

질문17

오직 task 이름들만 표시하도록 Ansible 실행의 출력 포맷을 어떻게 변경할 것인가?

Answer

해답은 “callback plugin” 이다. 여러분이 알고 있는 것만 바꿀것만 아니라 Ansible 에서 다른 이벤트를 기반으로 여러분이 원하는 모든것을 할 수 있다. 그래서 유사한 질문이 있을 수 있다: “어떻게 파일에 모든 것을 기록할 수 있나?” 그리고 대답은 여전히 callback plugin 일 수 있다.

여기에는 여러분이 callback plugins 에 대해서 알아야할 몇가지 포인트가 있다.

    • Ansible 트리에 몇가지 callback plugins 가 있다.
    • callback plugin을 활성화하기 위해서, ansible.cfg 에 다음과 같은 것을 포함해야 한다.
    • Ansible 실행에 기본 표준 출력을 바꾸기 위해서는, ansible.cfg 를 다음과 같이 바꿔라.
  • 새로운 callback plugin 을 개발할때, 부모 클래스 “CallbackBase” 로부터 상속이 필요하며 다음의 메소드를 오버라이드(override) 해야 한다.
    • v2_runner_on_skipped
    • v2_runner_on_unreachable
    • v2_runner_on_ok
    • v2_runner_on_failed

Callback plugin 은 여러분의 Ansible 실행을 커스터마이징을 위한 좋은 방법이고 여러분이 Ansible 아웃풋(Output)을 소비하는 방법이다.

질문18

다음의 컨텐츠를 포함하는 파일 ‘/tmp/excercise’ 가 있다.

하나의 Task 를 가지고, 다음과 같이 컨텐츠를 바꿔라.

Answer

새로운 컨셉이 아닌, 두개의 아이템을 매번 반복하는 곳에서 약간의 loop 문을 응용한 것이다. (regexp 과 line)

주목할 것은 이 문제를 ‘blockinfile’ 로 해결할 수도 있다.

질문19

문자열을 대문자로 바꾸는 필터를 작성해라.

Answer

우리는 매우 단순한 필터(filter)를 작성했다. 필터를 작성하는 Ansbile 을 마스터할때 자신의 것으로 하고 싶은 좋은 스킬인데, 거기에는 몇가지 이유가 있다.

첫째로, 믿던 안 믿던, 필터는 몇몇 게이스에서 여러분의 playbook 들을 좀 더 읽기편하게 해준다. 특히, 여러분이 아주 긴 명령어를 사용할때 사용자는 무엇을 왜 작성했는지 이해하는데 몇분이 소요된다. ‘hostname_to_ip’ 는 이해하기 아주 쉽다. right?

게다가, Ansible 의 모든 것을 맹목적으로 사용하지 마라. 이런것이 2차면접에서 의미있는 것은 아니다. 다른 사람이 이해하기 쉽고 성능에 영향을 미치지 않지만 어떤 경우에도 이를 고수하지 않을 경우 가능하면 Ansible 을 사용해라.

질문20

마지막 질문은 질문 요약이다. 10개의 지문이 있고 그것이 true 나 false 인지를 정해라.

    1. Module은 Task 의 집합이다.
    2. 특정한 Module 대신에 shell 이나 command 를 사용하는게 낫다.
    3. Host 팻츠(facts)는 play 변수들을 무시한다.
    4. Role 은 vars, meta 그리고 handler 를 포함할 수도 있다.
    5. 다이나믹 인벤토리는 외부 소스로부터 정보룰 추출함으로써 생성된다.
    6. 4칸 보다 2칸의 들여쓰기를 사용하는 것이 좋은 모범 사례다.
    7. 다음의 Task 는 성공적으로 실행될 것이다.
  1. ‘notify’ 는 Handler 를 트리거(Trigger)하는데 사용 된다.
  2. “hosts:all:!controllers” 는 ‘hosts 그룹에 controller 만 실행하라’ 라는 것이다.
  3. 기본 Role 은 role 변수를 무시한다.

Answer

  1. False play 는 Task들의 집합이다. Task 는 특정 모듈(Module)을 실행하는 것이다.
  2. False Shell 이나 Command 를 사용하는 것 좀 더 빠를 수 있지만, 일반적으로 Ansible 사용자를 위해서 더 쉽게 읽을수 있도록 언제나 특정 모듈을 사용하는 것이 좋습니다.
  3. False Play 변수들은 host 팻츠(Facts) 를 무시한다.
  4. True
  5. True OpenStack 과 같은 클라우드나 LDAP 일 수도 있다.
  6. False 이것은 정말 말이 안된다.
  7. Depends playbook 이나 role dl ‘become: yes’ 를 가지고 있다면, 이것은 성공적으로 실행되겠지만 그렇지 않다면 퍼미션때문에 실패할 것이다.
  8. True
  9. False Controller 들을 제외한 모든 hosts 를 대상으로 실행하라는 뜻이다.
  10. False Role 변수들은 role 기본값을 무시한다.

Practice is everything

여러분이 대부분의 질문에 올바르게 대답할 수 있었다면,이것은 Ansible 컨셉과 사용에 여러분이 익숙해 있다는 것을 확실하게 말해준다. 하지만 기억해야한다. 인터뷰 질문에 답하는것만이 아닌 연습만이 최고다.

더 많은 인터뷰 질문들

더 많은 인터뷰 질문이나 Ansible 을 배울때 검토할 주제의 체크리스트는 Github 저장소를 방문해라.

[Ansible] hosts did not meet host_list requirements 메시지 처리하기

Ansible 을 사용할때에 인벤토리 파일에 대해서 가끔 “hosts did not meet host_list requirements, check plugin documentation if this is unexpected” 메시지를 보게 된다. 이 메시지는 ‘ansible -vvv ‘ 처럼 -v 옵션을 주면 보인다.

이 메시지는 인벤토리 파일 형식으로 인한 것으로 ini 형식을때에 주로 나온다. 하지만 인벤토리 파일 형식이 ini 형식임을 ansible 이 인지하지 못해서 벌어지는 일인데, 이는 ansible.cfg 파일에 다음과 같이 함으로써 없앨 수 있다.