GitOps
고친 사람 github-actions[bot]
GitOps 는 서버와 서비스를 Git 저장소에 적힌 모습대로 맞춰 두는 운영 방식입니다. 사람은 시스템을 직접 만지지 않고 저장소의 파일만 고칩니다. 그러면 프로그램이 그 변경을 읽어 시스템에 반영합니다. 무엇이 언제 누구 손으로 바뀌었는지가 저장소 이력에 남습니다.
쉽고 빠른 이해
GitOps 는 운영을 코드 고치듯 하는 방식입니다. 웹 서버를 세 대에서 다섯 대로 늘리고 싶으면 설정 파일의 숫자 3 을 5 로 고쳐 올립니다. 서버에 접속해 명령을 치지 않습니다.
이렇게 하는 까닭은 손으로 한 변경이 흔적을 안 남기기 때문입니다. 누가 서버에서 설정을 바꾸면 무엇을 왜 바꿨는지 아무도 모릅니다. 저장소를 거치면 모든 변경이 리뷰를 받고 이력에 남습니다. 되돌릴 때도 같은 길을 씁니다. 지난 변경을 지우지 않습니다. 그 변경을 거꾸로 적은 변경을 하나 더 올립니다.
어떻게 도나:
- 사람이 설정 파일을 고쳐 변경 요청을 올립니다. 동료가 리뷰한 뒤 합칩니다
- 시스템 곁에 있는 프로그램이 저장소를 주기적으로 읽어 옵니다
- 저장소의 모습과 지금 시스템의 모습이 다르면 저장소 쪽으로 맞춥니다
대가도 있습니다. 급할 때 서버에서 바로 고친 것은 프로그램이 다시 저장소 모습으로 되돌려 버립니다. 비밀번호 같은 값은 저장소에 그냥 적을 수 없어 따로 다뤄야 합니다. 데이터베이스 안의 데이터처럼 파일로 적을 수 없는 것은 이 방식 밖에 남습니다. 그래서 시스템의 모습을 파일로 적을 수 있는 곳, 여러 사람이 함께 고치는 곳에 씁니다.
상세
이 절은 먼저 GitOps 를 이루는 네 약속을 봅니다. 그다음 변경 하나가 저장소에서 시스템까지 가는 길을 따라갑니다. 예로는 웹 서버 대수를 세 대에서 다섯 대로 늘리는 일 하나를 끝까지 씁니다. 마지막으로 이 방식이 무엇을 잃는지를 봅니다.
저장소가 정답인 운영
Git 은 파일의 변경 이력을 남기는 버전관리 도구입니다. 변경 하나하나를 커밋이라는 단위로 쌓습니다. 앞의 커밋에 적힌 모습은 언제든 다시 꺼내 볼 수 있습니다. 파일과 그 이력을 담아 두는 곳이 저장소입니다.
GitOps 에서는 이 저장소가 시스템의 정답지입니다. 「웹 서버는 세 대, 서버에 올릴 프로그램은 1.4 판」 같은 내용이 저장소의 파일에 적혀 있습니다. 시스템이 이 파일과 다르면 틀린 쪽은 시스템입니다. 이렇게 믿을 곳을 한 곳으로 정해 두는 것을 단일 진실 원천이라고 합니다.
이름은 Git 과 운영(Operations)을 붙여 지었습니다. 개발자가 코드를 다루던 방법을 그대로 운영에 가져온다는 뜻입니다.
네 가지 약속
GitOps 로 굴리는 시스템은 보통 네 가지를 갖춥니다. 넷은 차례로 앞의 것 위에 얹힙니다.
| 약속 | 뜻 | 없으면 |
|---|---|---|
| 선언적 | 순서가 아니라 끝났을 때의 모습을 적는다 | 저장소와 시스템을 비교할 기준이 없다 |
| 버전이 남고 안 바뀐다 | 적힌 모습은 이력으로 쌓이고 지난 기록을 고치지 않는다 | 무엇이 언제 바뀌었는지 못 따라간다 |
| 자동으로 끌어온다 | 시스템 쪽 프로그램이 저장소를 읽어 온다 | 누군가 밀어 넣어 줘야 반영된다 |
| 계속 맞춘다 | 시스템을 꾸준히 살펴 저장소 모습으로 되돌린다 | 한 번 맞춘 뒤 어긋나도 모른다 |
첫째 약속은 선언적 설정입니다. 「서버를 두 대 더 띄워라」가 아니라 「서버가 다섯 대 있어야 한다」라고 적는 방식입니다. 결과를 적어 두면 지금 몇 대인지와 상관없이 같은 파일로 같은 결과에 닿습니다.
적혀 있어야 할 모습을 원하는 상태라고 부릅니다. 지금 시스템이 실제로 놓인 모습은 실제 상태입니다. GitOps 의 일은 이 둘을 같게 만드는 것입니다.
끌어오는 프로그램과 조정 루프
셋째와 넷째 약속을 맡는 것은 시스템 곁에서 늘 도는 프로그램입니다. 이런 프로그램이 에이전트입니다. 사람 대신 정해진 일을 되풀이하는 프로그램이라는 뜻입니다.
에이전트는 같은 일을 끝없이 되풀이합니다. 한 바퀴는 세 단계입니다. 저장소에서 원하는 상태를 읽습니다. 시스템의 실제 상태를 살핍니다. 둘이 다른 만큼만 고칩니다. 이 되풀이를 조정 루프라고 부릅니다. 온도 조절기도 같은 모양입니다. 방 온도를 재어 설정 온도와 다르면 난방을 켭니다.
flowchart TD
A["저장소에서 원하는 상태를 읽는다"] --> B["시스템의 실제 상태를 살핀다"]
B --> C{"둘이 같은가"}
C -->|같다| D["잠시 기다린다"]
C -->|다르다| E["다른 만큼만 고친다"]
E --> D
D --> A
루프에는 끝이 없습니다. 변경을 반영한 뒤에도 에이전트는 계속 살핍니다. 그래서 누가 서버에 들어가 손으로 설정을 바꾸면, 다음 바퀴에서 그 변경이 저장소 모습으로 되돌아갑니다. 시스템이 적힌 모습에서 조금씩 벗어나는 일이 구성 드리프트입니다. 조정 루프가 이것을 계속 지웁니다.
변경 하나가 지나가는 길
웹 서버를 세 대에서 다섯 대로 늘리는 일로 따라가 보겠습니다. 사람과 에이전트가 각각 무엇을 하는지를 봅니다.
- 개발자가 설정 파일의 숫자를 고쳐 풀 리퀘스트를 올립니다. 풀 리퀘스트는 「이 변경을 합쳐 달라」는 요청입니다
- 동료가 변경을 읽고 코드 리뷰를 한 뒤 저장소의 기준 브랜치에 합칩니다. 브랜치는 커밋이 이어지는 한 갈래입니다. 기준 브랜치는 시스템에 반영할 모습을 담는 갈래입니다
- 에이전트가 다음 바퀴에 저장소를 읽습니다. 서버가 두 대 모자란 것을 알아챕니다
- 에이전트가 두 대를 더 띄웁니다. 이제 실제 상태와 원하는 상태가 같습니다
이 길에서 사람은 서버에 한 번도 접속하지 않았습니다. 사람이 한 일은 파일 한 줄을 고치고 리뷰를 받은 것뿐입니다.
되돌릴 때도 같은 길을 씁니다. 다섯 대가 문제였다면 그 커밋을 지우지 않습니다. 3 을 5 로 바꾼 것을 거꾸로 적은 커밋, 곧 되돌리는 커밋을 하나 더 합칩니다. 이력은 지워지지 않고 앞으로만 자랍니다. 에이전트는 저장소가 다시 세 대를 가리키는 것을 보고 두 대를 내립니다. 롤백이 새 절차가 아니라 평소의 변경과 같은 절차가 됩니다.
밀어 넣기와 끌어오기
GitOps 가 나오기 전에도 저장소에서 배포를 시작하는 방식은 있었습니다. 대개 지속적 통합(CI, Continuous Integration) 서버가 그 일을 했습니다. 지속적 통합은 커밋이 들어올 때마다 빌드와 테스트를 자동으로 돌리는 일입니다. 이 서버가 테스트 뒤에 운영 시스템에 접속해 변경을 밀어 넣었습니다.
GitOps 는 방향을 뒤집습니다. 바깥에서 밀어 넣지 않습니다. 시스템 곁의 에이전트가 저장소를 끌어옵니다. 두 방식은 누가 운영 시스템의 자격 증명을 쥐느냐에서 갈립니다. 자격 증명은 시스템에 들어가도 된다는 것을 증명하는 값입니다. 비밀번호나 접근 키가 그렇습니다.
| 밀어 넣기 | 끌어오기 | |
|---|---|---|
| 반영을 시작하는 쪽 | 바깥의 지속적 통합 서버 | 시스템 곁의 에이전트 |
| 운영 시스템의 자격 증명을 쥐는 쪽 | 바깥의 서버 | 시스템 안쪽의 에이전트 |
| 반영 뒤에 생긴 어긋남 | 다음 배포 때까지 모른다 | 다음 바퀴에 되돌린다 |
끌어오기에서는 자격 증명이 운영 시스템 밖으로 나가지 않습니다. 바깥 서버가 뚫려도 운영 시스템에 들어갈 열쇠는 거기 없습니다. 아래 그림은 두 방식에서 자격 증명이 어느 쪽에 있는지, 누가 경계를 넘어 일을 시작하는지를 보입니다.
flowchart TD
subgraph PUSH["밀어 넣기"]
P1["저장소"] --> P2["지속적 통합 서버<br/>자격 증명을 쥔다"]
P2 -->|"바깥에서 경계를 넘어 들어간다"| P3
subgraph SYS1["운영 시스템"]
P3["서버들"]
end
end
subgraph PULL["끌어오기"]
Q1["저장소"]
subgraph SYS2["운영 시스템"]
Q2["에이전트<br/>자격 증명을 쥔다"] --> Q3["서버들"]
end
Q1 -->|"안쪽 에이전트가 요청해 읽어 온다"| Q2
end
P3 ~~~ Q1
이 방식이 잃는 것
GitOps 는 모든 변경을 저장소로 모읍니다. 그 대가는 저장소를 거치지 않는 일이 불편해지는 것입니다.
첫째, 급한 손 수정이 살아남지 못합니다. 장애 중에 서버에서 설정을 바로 고쳐도 에이전트가 다음 바퀴에 되돌립니다. 급한 수정도 저장소를 거쳐야 하므로 리뷰와 반영 시간만큼 늦어집니다.
둘째, 비밀 정보를 저장소에 그냥 적을 수 없습니다. 비밀번호를 평문으로 커밋하면 저장소를 읽을 수 있는 사람 모두가 봅니다. 이력은 지우지 않는 것이 원칙이라 나중에 지우기도 어렵습니다. 그래서 암호화해 적거나 바깥 보관소를 가리키는 방법을 따로 붙여야 합니다.
셋째, 파일로 적을 수 없는 상태는 이 방식 밖에 남습니다. 데이터베이스에 쌓인 데이터가 그렇습니다. 테이블 모양을 바꾸는 스키마 마이그레이션처럼 정해진 순서로 한 번만 해야 하는 일도 결과만 적는 방식에 잘 안 맞습니다.
넷째, 반영이 즉시 일어나지 않습니다. 에이전트가 다음 바퀴에 저장소를 읽을 때까지 변경은 기다립니다. 합친 뒤 반영까지 틈이 생깁니다. 그 사이에는 저장소와 시스템이 다릅니다.
그래서 GitOps 는 두 조건이 갖춰진 곳에 맞습니다. 시스템의 모습을 파일로 적을 수 있어야 합니다. 여러 사람이 같은 시스템을 고쳐야 합니다. 손 수정이 잦거나 지켜야 할 상태 대부분이 데이터인 시스템에는 덜 맞습니다.
관련 항목
GitOps 가 바탕으로 삼는 운영 원칙
코드형 인프라 · 선언적 설정 · 단일 진실 원천 · 불변 인프라 · 멱등성 · 설정 관리
GitOps 가 맞추는 두 상태와 그 어긋남
원하는 상태 · 실제 상태 · 구성 드리프트 · 드리프트 탐지 · 조정 루프
GitOps 의 변경이 거치는 개발 도구
Git · 버전관리 · 저장소 · 커밋 · 브랜치 · 풀 리퀘스트 · 코드 리뷰 · 감사 로그
GitOps 가 속하는 배포 흐름
지속적 통합 · 지속적 전달 · 지속적 배포 · 커밋에서 배포까지 · 부분 배포 · 롤백 · 자동 롤백
GitOps 를 구현한 도구와 그 발판
Argo CD · Flux · Kubernetes · 테라폼 · 컨테이너 이미지 · 에이전트
GitOps 를 굴리며 따로 챙기는 보안 대상
다른 이름: 깃옵스 · Git Ops · 깃 옵스