집합 자료형은 중복되지 않는 고유한 요소들의 모음을 저장하는 자료형으로, 여러 가지 실무 상황에서 유용하게 사용할 수 있다. 집합은 중괄호 {}를 사용하여 생성하며, 다양한 집합 연산을 지원한다. 아래에서는 집합 자료형을 실무에서 사용할 수 있는 몇 가지 상황을 설명해보겠다.
1. 중복 제거
가장 일반적인 집합의 사용 사례는 중복된 데이터를 제거하는 것이다. 예를 들어, 고객 이메일 목록에서 중복된 이메일 주소를 제거할 때 유용하다.
집합은 중복을 허용하지 않기 때문에, 데이터 무결성을 유지하는 데 유용하다. 예를 들어, 사용자 ID나 제품 코드와 같이 고유해야 하는 데이터를 저장할 때 사용한다.
예시
user_ids = {"user1", "user2", "user3"}
# 새로운 사용자 ID 추가
user_ids.add("user4")
print(user_ids) # 출력: {'user1', 'user2', 'user3', 'user4'}
# 중복된 사용자 ID 추가 시도
user_ids.add("user2")
print(user_ids) # 출력: {'user1', 'user2', 'user3', 'user4'} (중복 추가되지 않음)
4. 빠른 멤버십 테스트
집합은 특정 요소가 집합에 존재하는지 빠르게 확인할 수 있다. 이는 대규모 데이터에서 특정 요소를 검색할 때 유용하다.
예시
# 대규모 데이터 집합 생성
large_set = set(range(1000000))
# 특정 요소 존재 여부 확인
print(999999 in large_set) # 출력: True
print(1000000 in large_set) # 출력: False
5. 태그 시스템
집합은 태그 시스템을 구현할 때 유용하다. 예를 들어, 블로그 게시물에 여러 태그를 추가하고, 특정 태그를 가진 게시물을 검색할 때 사용한다.
예시
# 게시물에 태그 추가
post_tags = {"python", "programming", "tutorial"}
# 새로운 태그 추가
post_tags.add("coding")
print(post_tags) # 출력: {'python', 'programming', 'tutorial', 'coding'}
# 특정 태그 존재 여부 확인
print("python" in post_tags) # 출력: True
print("java" in post_tags) # 출력: False
결론
집합 자료형은 중복 제거, 집합 연산, 데이터 무결성 유지, 빠른 멤버십 테스트, 태그 시스템 등 다양한 실무 상황에서 유용하게 사용할 수 있다. 집합의 특성과 장점을 이해하고 적절히 활용하면 데이터 처리와 분석을 더욱 효율적으로 수행할 수 있다.
프로그래밍을 할 때 리스트와 튜플을 사용하여 데이터를 저장할 수 있다. 이 두 자료형은 많은 면에서 비슷하지만, 메모리 사용량에서는 차이가 있다. 이 글에서는 리스트와 튜플의 메모리 사용량 차이를 설명해보겠다.
리스트와 튜플의 메모리 사용량 비교
리스트와 튜플은 각각 데이터를 저장하는 방식이 다르기 때문에 메모리 사용량에서도 차이가 난다. 일반적으로 튜플이 리스트보다 메모리를 덜 사용한다.
예시
# 리스트와 튜플 생성
a_list = [1, 2, 3]
a_tuple = (1, 2, 3)
# 메모리 사용량 확인
print(a_list.__sizeof__()) # 출력: 64
print(a_tuple.__sizeof__()) # 출력: 48
위 예시에서 볼 수 있듯이, 동일한 데이터를 저장할 때 리스트는 64바이트를 사용하고, 튜플은 48바이트를 사용한다.
메모리 사용량 차이의 이유
가변성:
리스트는 가변적이어서 요소를 추가하거나 삭제할 수 있다. 이를 위해 리스트는 추가적인 메모리를 할당하여 데이터를 저장하고 관리해야 한다. 반면, 튜플은 불변적이어서 한 번 생성되면 변경할 수 없다. 따라서 튜플은 고정된 메모리만 할당하면 된다.
오버 할당:
리스트는 요소를 추가할 때마다 메모리를 재할당하는 비용을 줄이기 위해 오버 할당(over-allocation) 기법을 사용한다. 이는 리스트가 더 많은 메모리를 사용할 수 있게 한다. 반면, 튜플은 이러한 오버 할당이 필요 없으므로 더 적은 메모리를 사용한다[1][2].
구조적 차이:
리스트는 각 요소에 대한 포인터를 저장하는 데 추가 메모리를 사용한다. 반면, 튜플은 이러한 포인터를 저장하지 않아 더 적은 메모리를 사용한다[1].
리스트는 여러 데이터를 순서대로 저장할 수 있는 자료형이다. 리스트는 대괄호 []로 감싸서 만들고, 각 요소는 쉼표 ,로 구분한다. 리스트의 가장 큰 특징은 변경 가능하다는 점이다. 즉, 리스트에 있는 데이터를 수정, 추가, 삭제할 수 있다.
예시
# 리스트 생성
fruits = ["사과", "바나나", "딸기"]
# 리스트 요소 변경
fruits[1] = "오렌지" # 바나나를 오렌지로 변경
print(fruits) # 출력: ['사과', '오렌지', '딸기']
# 리스트에 요소 추가
fruits.append("포도")
print(fruits) # 출력: ['사과', '오렌지', '딸기', '포도']
# 리스트에서 요소 삭제
fruits.remove("딸기")
print(fruits) # 출력: ['사과', '오렌지', '포도']
튜플 (Tuple)
튜플은 리스트와 비슷하게 여러 데이터를 순서대로 저장할 수 있는 자료형이다. 하지만 튜플은 소괄호 ()로 감싸서 만들고, 리스트와 달리 변경 불가능하다. 즉, 한 번 생성된 튜플의 요소는 수정, 추가, 삭제할 수 없다.
예시
# 튜플 생성
colors = ("빨강", "초록", "파랑")
# 튜플 요소 접근
print(colors[1]) # 출력: 초록
# 튜플 요소 변경 시도 (오류 발생)
# colors[1] = "노랑" # 오류: 튜플은 변경할 수 없음
# 튜플에 요소 추가 시도 (오류 발생)
# colors.append("노랑") # 오류: 튜플은 변경할 수 없음
리스트와 튜플의 차이점 정리
특징 리스트 (List) 튜플 (Tuple)
생성 방법
대괄호 [] 사용
소괄호 () 사용
변경 가능 여부
변경 가능 (요소 수정, 추가, 삭제 가능)
변경 불가능 (요소 수정, 추가, 삭제 불가)
사용 예시
동적으로 변하는 데이터 관리에 유용하다
고정된 데이터 관리에 유용하다
결론
리스트와 튜플은 여러 데이터를 관리할 때 매우 유용한 자료형이다. 리스트는 데이터를 자유롭게 수정, 추가, 삭제할 수 있어 유연성이 높다. 반면, 튜플은 한 번 생성되면 변경할 수 없기 때문에 데이터의 무결성을 유지하는 데 유리하다. 이 두 자료형의 차이를 이해하고 상황에 맞게 사용하는 것이 중요하다.
2차원 배열은 숫자나 문자를 정리해서 저장할 수 있는 표와 같은 것이다. 엑셀이나 구글 스프레드시트를 생각해보면 쉽게 이해할 수 있다. 표의 각 칸에는 하나의 값이 들어가고, 이 값들은 행과 열로 구분된다.
2차원 배열의 예시
예를 들어, 다음과 같은 표가 있다고 하자:
0열 1열 2열
0행
1
2
3
1행
4
5
6
2행
7
8
9
이 표는 3개의 행과 3개의 열로 이루어져 있다. 각 칸에는 숫자가 들어있다. 이 표를 2차원 배열이라고 부른다.
파이썬에서 2차원 배열 만들기
파이썬에서는 리스트라는 것을 사용해서 2차원 배열을 만들 수 있다. 리스트는 여러 개의 값을 한 곳에 모아놓는 방법이다. 2차원 배열을 만들기 위해서는 리스트 안에 리스트를 넣으면 된다.
array = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
위의 코드는 3x3 크기의 2차원 배열을 만든다. 첫 번째 리스트 [1, 2, 3]는 첫 번째 행을 나타내고, 두 번째 리스트 [4, 5, 6]는 두 번째 행을 나타낸다.
2차원 배열에서 값 꺼내기
2차원 배열에서 특정 값을 꺼내려면 행과 열의 위치를 알려줘야 한다. 예를 들어, 첫 번째 행과 두 번째 열에 있는 값을 꺼내려면 다음과 같이 하면 된다.
value = array[0][1] # 결과는 2
여기서 array은 첫 번째 행(0행)과 두 번째 열(1열)에 있는 값을 의미한다. 파이썬에서는 숫자를 셀 때 0부터 시작한다는 점을 기억하자.
2차원 배열에서 부분 배열 꺼내기
2차원 배열에서 여러 개의 값을 한꺼번에 꺼내는 것도 가능하다. 이를 슬라이싱이라고 한다. 예를 들어, 첫 번째와 두 번째 행을 꺼내려면 다음과 같이 한다.
rows = array[0:2] # 결과는 [[1, 2, 3], [4, 5, 6]]
여기서 array[0:2]는 첫 번째 행(0행)과 두 번째 행(1행)을 의미한다.
2차원 배열에서 인덱싱과 슬라이싱을 활용하면 특정 행, 열 또는 부분 배열을 쉽게 추출할 수 있다. 이를 통해 데이터 분석, 이미지 처리 등 다양한 분야에서 효율적으로 데이터를 다룰 수 있다. 아래 예제는 NumPy 라이브러리를 사용하여 2차원 배열을 처리하는 방법을 보여준다.
예시: 2차원 배열 생성 및 인덱싱, 슬라이싱
먼저, NumPy를 사용하여 2차원 배열을 생성하고, 인덱싱과 슬라이싱을 통해 특정 부분을 추출하는 예제를 살펴보자.
import numpy as np
# 2차원 배열 생성
array = np.array([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20]
])
# 배열 출력
print("원본 배열:")
print(array)
인덱싱 예제
특정 행과 열의 요소를 추출하는 방법이다.
# 두 번째 행의 세 번째 요소 (8) 추출
element = array[1, 2]
print("\\\\n두 번째 행의 세 번째 요소:", element)
# 마지막 행의 마지막 요소 (20) 추출
element = array[-1, -1]
print("마지막 행의 마지막 요소:", element)
슬라이싱 예제
배열의 특정 부분을 추출하는 방법이다.
# 첫 두 행과 첫 세 열 추출
sub_array = array[:2, :3]
print("\\\\n첫 두 행과 첫 세 열:")
print(sub_array)
# 두 번째 행부터 끝까지, 세 번째 열부터 네 번째 열까지 추출
sub_array = array[1:, 2:4]
print("\\\\n두 번째 행부터 끝까지, 세 번째 열부터 네 번째 열까지:")
print(sub_array)
# 모든 행에서 두 번째 열만 추출
column = array[:, 1]
print("\\\\n모든 행에서 두 번째 열:")
print(column)
# 모든 열에서 세 번째 행만 추출
row = array[2, :]
print("\\\\n모든 열에서 세 번째 행:")
print(row)
문자열 인덱싱은 문자열의 특정 위치에 있는 문자를 가져오는 방법이다. 인덱스는 0부터 시작하며, 음수 인덱스를 사용하면 문자열의 끝에서부터 역순으로 접근할 수 있다.
# 문자열 설정
text = "Hello, World!"
# 인덱싱 예제
print(text[0]) # 출력: H (첫 번째 문자)
print(text[7]) # 출력: W (여덟 번째 문자)
print(text[-1]) # 출력: ! (마지막 문자)
print(text[-5]) # 출력: o (뒤에서 다섯 번째 문자)
문자열 슬라이싱
문자열 슬라이싱은 문자열의 일부분을 추출하는 방법이다. 슬라이싱은 [start:end:step] 형식을 사용하며, start는 시작 인덱스, end는 끝 인덱스(포함되지 않음), step은 간격을 의미한다.
인덱싱과 슬라이싱을 동시에 활용한 실무 예제 - 로그 파일에서 날짜와 오류 메시지 추출하기
문자열 인덱싱과 슬라이싱을 동시에 활용하면 문자열의 특정 부분을 효율적으로 추출하고 조작할 수 있다. 예를 들어, 로그 파일에서 특정 정보를 추출하거나, 텍스트 데이터에서 특정 패턴을 찾는 작업에 유용하다.
로그 파일의 각 줄에서 날짜와 오류 메시지를 추출하는 예제를 살펴보자. 로그 파일의 형식은 다음과 같다:
2024-08-07 12:34:56 ERROR: Something went wrong
2024-08-07 12:35:56 INFO: All systems operational
2024-08-07 12:36:56 ERROR: Another error occurred
이 로그 파일에서 날짜와 오류 메시지만 추출하는 코드를 작성해보자.
# 로그 파일의 각 줄을 리스트로 저장
log_lines = [
"2024-08-07 12:34:56 ERROR: Something went wrong",
"2024-08-07 12:35:56 INFO: All systems operational",
"2024-08-07 12:36:56 ERROR: Another error occurred"
]
# 날짜와 오류 메시지를 추출하는 함수
def extract_error_info(log_lines):
for line in log_lines:
if "ERROR" in line:
# 날짜 추출 (인덱싱과 슬라이싱을 동시에 활용)
date = line[:10] # 처음 10글자: 2024-08-07
# 오류 메시지 추출
error_message = line[line.index("ERROR:") + 7:] # "ERROR:" 다음부터 끝까지
print(f"Date: {date}, Error: {error_message}")
# 함수 호출
extract_error_info(log_lines)
결과
Date: 2024-08-07, Error: Something went wrong
Date: 2024-08-07, Error: Another error occurred
설명
날짜 추출: line[:10]을 사용하여 문자열의 처음 10글자를 추출한다. 이는 날짜를 의미한다.
오류 메시지 추출: line.index("ERROR:") + 7을 사용하여 "ERROR:" 문자열의 위치를 찾고, 그 이후의 문자열을 추출한다.
이 예시는 인덱싱과 슬라이싱을 동시에 활용하여 문자열에서 필요한 정보를 효율적으로 추출하는 방법을 보여준다. 이러한 기법은 로그 파일 분석, 데이터 전처리 등 다양한 실무 상황에서 유용하게 사용될 수 있다.
자료형이란 프로그래밍을 할 때 쓰이는 숫자, 문자열 등과 같이 자료 형태로 사용하는 모든 것을 뜻한다.
예시: Python에서 자료형 이해의 중요성
상황 설명:
Alice는 Python을 배우기 시작한 초보 프로그래머다. 그녀는 계산기를 만드는 프로젝트를 진행 중이다. 그러나 자료형에 대한 이해가 부족하여 여러 가지 문제에 직면하게 된다.
잘못된 접근: Alice는 자료형에 대한 이해 없이 바로 코딩을 시작했다. 그녀는 사용자로부터 입력을 받아 두 숫자를 더하는 간단한 계산기를 만들려고 했다.
# Alice의 코드
num1 = input("첫 번째 숫자를 입력하세요: ")
num2 = input("두 번째 숫자를 입력하세요: ")
result = num1 + num2
print("결과: ", result)
Alice는 두 숫자를 더한 결과가 기대와 다르다는 것을 발견했다. 예를 들어, '3'과 '5'를 입력했을 때 결과는 '35'가 나왔다.
문제 분석: Alice는 input 함수가 문자열을 반환한다는 사실을 몰랐다. 따라서 num1과 num2는 문자열로 저장되었고, 문자열끼리의 덧셈은 문자열을 이어붙이는 결과를 초래했다.
올바른 접근: 자료형을 이해한 후, Alice는 사용자로부터 입력받은 값을 정수형으로 변환해야 한다는 것을 알게 되었다.
# 수정된 코드
num1 = int(input("첫 번째 숫자를 입력하세요: "))
num2 = int(input("두 번째 숫자를 입력하세요: "))
result = num1 + num2
print("결과: ", result)
이제 Alice의 계산기는 올바르게 작동한다. '3'과 '5'를 입력했을 때 결과는 '8'이 된다.
이 예시는 자료형을 이해하지 않고 프로그래밍을 시작하면 발생할 수 있는 문제를 보여준다. 자료형을 충분히 이해하는 것은 프로그래밍의 기본이자 핵심이다. 자료형을 이해함으로써 Alice는 올바른 계산기를 만들 수 있었고, 이는 다른 복잡한 프로그램을 작성할 때도 중요한 기초가 된다.
기본 대상 브랜치는 잠겨 있습니다. 병합은 PR을 통해 이루어집니다. PR은 관련 작업 항목을 참조합니다. 커밋 기록은 일관되고 커밋 메시지는 정보(내용, 이유)를 제공한다. 일관된 브랜치 이름 지정 규칙. 리포지토리 구조에 대한 명확한 문서화. secret은 커밋 기록에 포함되지 않거나 공개되지 않습니다. (자격 증명 스캔 참조) 공개 리포지토리는 OSS 가이드라인을 따르며, "공개 리포지토리의 기본 브랜치에 필요한 파일을 참조하세요." 를 적는다.
로그 데이터는 라벨로 분류됩니다. 라벨은 로그 데이터를 구분하고 쿼리하기 위한 메타데이터로, 키/값의 쌍으로 이루어져 있습니다. 예를 들어, {component="printer", location="f2c16", level="error"}와 같은 라벨 세트가 로그 메시지에 할당됩니다.
라벨 세트는 해시되어 고유한 '스트림 ID'를 생성합니다. 이 ID는 특정 로그 스트림을 식별하는 데 사용됩니다. 이미지에는 해시된 결과의 예로 3b2cea09797978fc가 있습니다.
청크의 생성과 저장:
동일한 라벨 세트를 가진 추가적인 로그 메시지들은 같은 '청크'에 추가됩니다. 예를 들어, "Printing is not supported by this printer", "Out of paper", "Too much paper"와 같은 다양한 로그 메시지가 모두 같은 라벨을 공유하므로 같은 청크에 저장됩니다.
이러한 청크는 채워진 후에 압축되고 저장됩니다.
청크 조회를 위한 인덱스:
청크를 빠르게 찾기 위해, 별도의 작고 분리된 인덱스가 유지됩니다. 이 인덱스를 통해 청크를 빠르게 조회할 수 있습니다.
라벨 값의 변화와 새로운 청크 생성:
만약 라벨의 키 또는 값이 달라지면, 다른 해시 값을 가지는 새로운 스트림과 새로운 청크가 생성됩니다. 예를 들어, {component="printer", location="f2c16", level="info"} 라벨 세트는 "Consider the environment before printing this log message"라는 로그 메시지와 함께 새로운 청크를 형성합니다.
결과값 설명: rate함수(초당 평균 증가율을 계산하는 함수)를 사용하여 5분(300초)동안 초당 평균 요청 증가율을 출력한것.
앞서 5m일때의 값이 약 20개이다. 즉 rate함수가 초당 평균증가율을 계산하는거니까 300초([5m])동안 약 20개 가량이 증가했으니까 20 / 300 하면 대략 0.066666667이 나온다.
그래프결과:
06시 9분에 처음 메트릭 수집이 시작됐고 5분뒤인 14분에 약 20개 가량의 결과값이 쌓였다.
그래서 위와같이 약 14분가량에 밸류값이 0.06666667에 가까운것을 알수있다.
레인지 백터로 5m을 줬을 때 최근 5분동안의 결과값을 타임스탬프 형식으로 가져오는것은 맞다. 여기서 오해하면 안되는게 rate 함수를 사용했을 때 최근 5분동안의 증가율만 결과값으로 반환하지만 이를 그래프로 표현했을때는 수집 시점부터의 수집값을 가지고 그래프를 그린다는것
cat taskfile.yaml
version: '3'
tasks:
hello:
cmds:
- echo 'Hello World from Task!'
silent: true
task hello
Hello World from Task!
말그대로 task들을 코드로 관리하는 도구
챗지피티 설명Taskfile의 주요 장점은 다음과 같습니다:
간단하고 명확한 문법: Taskfile은 가독성이 높고 쓰기 쉬운 문법을 제공합니다. 이는 개발자가 작업을 빠르게 정의하고 이해할 수 있게 해줍니다.
로컬 및 원격 실행 지원: Taskfile은 로컬 개발 환경과 원격 CI/CD 파이프라인에서 동일한 작업을 실행할 수 있게 해줍니다. 이는 개발 및 배포 과정의 일관성을 보장합니다.
작업 의존성 관리: Taskfile을 사용하면 작업 간의 의존성을 쉽게 정의하고 관리할 수 있습니다. 이는 작업 실행 순서를 자동화하고 복잡한 작업 흐름을 구성하는 데 도움이 됩니다.
재사용성 및 모듈화: Taskfile을 통해 정의된 작업은 재사용 가능하고 모듈화되어 있어, 다른 프로젝트나 파이프라인에서 쉽게 재사용할 수 있습니다.
확장성: Taskfile은 단순한 작업 실행부터 복잡한 파이프라인 구성까지 다양한 요구 사항을 수용할 수 있도록 설계되었습니다. 개발자는 필요에 따라 작업을 확장하고 사용자 정의할 수 있습니다.
통합 용이성: Taskfile은 GitHub Actions, Jenkins, GitLab CI 등 다양한 CI/CD 도구와 쉽게 통합될 수 있습니다. 이를 통해 개발 팀은 파이프라인을 효율적으로 관리하고 자동화할 수 있습니다.
Taskfile은 Makefile과 비교할 때 더 현대적이고 사용자 친화적인 대안으로, 개발자들이 작업을 더 효율적으로 관리하고 실행할 수 있게 해줍니다. 추가적인 질문이 있거나 더 자세한 정보가 필요하시면 언제든지 문의해 주세요.
Taskfile은 개발 과정에서 다양한 작업을 관리하기 위한 도구입니다. 이 도구를 사용하면 테스트 실행, 빌딩, 패키징, 배포 등의 작업을 선언적 방식으로 정의하고 자동화할 수 있습니다. Taskfile의 주요 목적은 작업 실행을 단순화하고, 개발자가 로컬 및 CI/CD 파이프라인 환경에서 동일한 작업을 쉽게 실행할 수 있도록 하는 것입니다.
msbuild라던가 gradle의 여러 버전별로 사용해야 할 때 파이프라인에서 각 gradle의 환경변수를 직접 잡아줄 필요 없이 task를 사용하면 손쉽게 버전별 도구를 사용할수있지 않을가 싶다.
version: '3'
tasks:
gradle6.1:
cmds:
- gradle6.1 wrapper --gradle-version=6.1
- ./gradlew build
desc: "Build the project with Gradle 6.1"
gradle7.2:
cmds:
- gradle7.2 wrapper --gradle-version=7.2
- ./gradlew build
desc: "Build the project with Gradle 7.2"
이외에도 docker compose up , down 조차도 어려워하는 고객들에게 task를 사용하여 명령어를 만들어주고 사용하라고 해도 좋을듯.
가장 베스트는 개발자들이 직접 이 taskfile이라는 도구를 사용하면서 개발(로컬피씨)환경과 빌드서버환경을 통일하면 가장 좋을듯하다.
본론만 말하기,쓸대없는 말 하지 말기, 미사여구 붙이지 말기 ex)자꾸 질문해서 미안한데.. 이런 쓸대없는말 하지 말기
청중 설정하기. 의도한 청중을 설정하고 질문하기 ex)스마트폰을 사용해본적 없는 사람을 위해 스마트폰 작동원리에 대한 개요를 설명해줘
복잡한 작업을 간단한 프롬프트로 세분화시켜라. ex) A로는 B를 만들고 만들어진 B를가지고 C와D를 만들어줘. C가지고는 C-1을 생성하고 D로는 D-1을 추가로 만들어줘 X ex) P1: A로 B 만들어줘. 그리고 만들어진 B를 추후 재사용할꺼니까 기억해 P2: 만들어진 B를가지고 C를 만들어줘. 그리고 만들어진 C를 추후 재사용할꺼니까 기억해 P3. 만들어진 B를 가지고 D를 만들어줘. 그리고 만들어진 D를 추후 재사용할꺼니까 기억해 P4. C로는 C-1을 만들어줘. P5. D로는 D-1을 만들어줘.
긍정 지시문 사용하기, 부정어 사용하지말기 ex) 반말 하지마 X 존댓말 해 O.
어린이 청자 설정하기 ex) 비전공자도 이해하기 쉽게 설명해줘 ex) 11살짜리도 이애할수 있게 설명해줘
팁준다고하기 ex) 더 나은 답변을 하면 $300K팁을 줄게. devops에 대해서 설명해줘
전통적인 컨테이너 방식 대신 Nix Shell을 사용하여 임시 환경을 생성하고 파괴하는 새로운 접근 방식을 탐구합니다. Nix Shell은 개발자가 필요한 도구를 포함한 환경을 쉽게 생성하고 사용 후 즉시 제거할 수 있는 효율적인 방법을 제공합니다. 이 접근 방식의 주요 장점은 다양한 운영 체제에서 일관된 개발 환경을 제공하면서도 필요할 때만 특정 도구를 사용할 수 있게 해준다는 점입니다.
임시 환경의 필요성: 개발자들이 필요에 따라 환경을 쉽게 생성하고 제거할 수 있는 능력은 효율적인 작업 흐름을 위해 필수적입니다. 임시 환경은 특히 개발, 테스트 및 빌드 파이프라인에서 유용합니다.
컨테이너의 한계: 컨테이너는 여러 환경에서 널리 사용되지만, 설정과 관리가 복잡할 수 있으며, 다양한 도구와 응용 프로그램의 설치 및 설정에 제한이 있을 수 있습니다.
Nix Shell의 소개: Nix Shell은 이러한 문제를 해결하기 위한 대안으로, 필요한 도구와 응용 프로그램을 포함한 커스텀 환경을 쉽게 생성할 수 있습니다. 이는 특히 여러 도구가 필요한 복잡한 프로젝트나 다양한 개발 요구 사항이 있는 팀에 유용합니다.
사용 사례와 예시: Nix Shell을 사용하여 GitHub CLI, Kubernetes, 그리고 다양한 개발 도구를 포함한 환경을 신속하게 설정하는 과정을 보여줍니다. 이는 개발자가 복잡한 설치 과정 없이도 필요한 모든 도구에 즉시 접근할 수 있게 해줍니다.
플랫폼 독립성: Nix Shell은 macOS, Windows, Linux 등 다양한 운영 체제에서 동일한 방식으로 작동합니다. 이는 개발자가 운영 체제의 차이에 구애받지 않고 일관된 환경을 유지할 수 있게 해줍니다.
효율성과 생산성 향상: Nix Shell을 사용하면 개발자가 프로젝트에 필요한 도구를 빠르고 쉽게 준비할 수 있으며, 사용하지 않을 때는 쉽게 제거할 수 있습니다. 이는 개발자의 시간을 절약하고 전반적인 생산성을 향상시킵니다.
App A가 있어야하고 이를 바라보는 App B, App B에 연결된 DB, DB에 연결된 DB User, 스키마가 있어야 한다. 이렇듯 애플리케이션이 구동하려면 여러가지 서비스간의 의존성을 고려해야 한다.
이러한 서비스간의 의존성은 과거에는 배포순서가 중요했다. 예를들어, 과거의 배포방식은 SSH로 서버에 직접 접속하거나 혹은 파이프라인 또는 스크립트로 배포를 했다. 즉, 정해진 스크립트(배포 순서)에 따라 서비스들이 배포됐기에 배포 순서가 중요했다.
그러나 k8s 환경에서는 배포 순서가 그다지 중요하지 않아졌다.
왜냐하면 k8s는 실패한 리소스의 배포를 계속 시도하므로 만약 잘못된 순서대로 배포된다해도 결국 애플리케이션은 정상적으로 동작하게 될 것이다.
하지만 과거의 관습(의존성을 배포순서로 가져가는것)을 k8s 환경에서 사용하는 경우가 많다.
우리가 중요하게 생각해야할 점은 k8s를 사용하는 현 시점에서 리소스의 종속성과 생성 순서에 대해 과도하게 걱정할 필요가 없다는 것이다. 오히려 시스템이 자연스럽게 일관성을 유지하도록 하고, 필요한 데이터나 정보에 기반한 종속성에 초점을 맞추는 것이 중요하다는 의미이다.
예를 들어, 애플리케이션이 데이터베이스에 접근하기 위해 필요한 접근정보가 준비되지 않았다면, 쿠버네티스는 자동으로 해당 애플리케이션의 생성을 지연시킨다.
즉, 리소스의 생성 순서보다는 해당 리소스가 제공하는 데이터의 가용성이 더 중요함을 의미한다.
Kubewarden은 쿠버네티스(Kubernetes) 클러스터의 보안과 정책 준수를 관리하기 위한 도구입니다.
Kubewarden을 사용하면, 클러스터에 어떤 파드(Pod, 쿠버네티스에서 애플리케이션을 실행하는 단위)가 생성되거나 업데이트될 때 적용되는 규칙이나 정책을 설정할 수 있습니다.
Kubewarden은 WebAssembly(WASM)와 쿠버네티스 admission controllers를 결합한 도구로, 다양한 언어로 작성된 정책을 컴파일하여 쿠버네티스에서 실행할 수 있게 해줍니다.
쿠버네티스의 Admission Controllers
쿠버네티스의 Admission Controllers는 쿠버네티스 API 서버로의 요청을 가로채서 검사하고, 수정하거나 거부하는 역할을 합니다.
이들은 쿠버네티스 클러스터에서 리소스(파드, 서비스 등)의 생성, 업데이트, 삭제 등의 요청이 처리되기 전에 특정 규칙이나 정책을 적용합니다.
예를 들어, 특정 파드가 너무 많은 CPU 자원을 요청하는 것을 막거나, 특정 네임스페이스에서만 리소스를 생성할 수 있도록 제한하는 등의 작업을 수행합니다.
Admission Controllers는 쿠버네티스의 보안과 정책 준수를 강화하는 데 중요한 역할을 합니다.
Kubewarden을 사용하면 정의된 정책을 적용하고, 이 정책들이 쿠버네티스 API로의 요청을 수락, 거부 또는 변경할 수 있습니다.
Kubewarden의 정책 모듈은 컨테이너 이미지로 참조되며, 이는 정책을 이미지에 저장하고 있다는 것을 의미합니다. 예를 들어, 특정 이미지가 권한 있는 파드의 실행을 방지하는 정책을 가지고 있을 수 있습니다.
예시
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
name: validate-pod-security-standards
spec:
module: registry://ghcr.io/kubewarden/policies/validate-pod-security-standards:v1.0.0
rules:
- apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
operations:
- CREATE
- UPDATE
mutating: false
settings:
requiredLabels: # 파드에 반드시 존재해야 하는 레이블들을 정의합니다.
- "app.kubernetes.io/name"
- "app.kubernetes.io/version"
requiredAnnotations: # 파드에 반드시 존재해야 하는 어노테이션을 정의합니다.
- "kubewarden.policy/owner"
enforceRunAsNonRoot: true # 파드가 Non-root 사용자로 실행되어야 한다는 요구사항을 설정합니다.
allowedCapabilities: [] # 파드에서 허용되는 추가적인 리눅스 기능(capabilities)을 비어 있는 배열로 설정하여 모든 추가 기능을 금지합니다.
이 설정에 따르면:
module: registry://ghcr.io/kubewarden/policies/validate-pod-security-standards:v1.0.0:Kubewarden 정책 모듈은 쿠버네티스 클러스터에서 파드의 보안 표준을 검증하는 데 사용됩니다. 이 모듈의 주요 목적과 기능은 다음과 같습니다:
requiredLabels: 모든 파드에는 **app.kubernetes.io/name**과app.kubernetes.io/version레이블이 있어야 합니다. 이는 파드가 어떤 애플리케이션에 속하는지와 애플리케이션의 버전을 명시하는 데 사용됩니다.
requiredAnnotations: 모든 파드에는kubewarden.policy/owner어노테이션이 있어야 합니다. 이는 정책의 소유자 또는 관리자를 지정하는 데 사용될 수 있습니다.
enforceRunAsNonRoot: 이 값이 **true**로 설정되면, 모든 파드는 루트가 아닌 사용자로 실행되어야 합니다. 이는 보안 관행에 따른 것입니다.
allowedCapabilities: 이 배열이 비어 있기 때문에, 파드에서 어떠한 추가 리눅스 기능도 허용되지 않습니다. 이는 파드가 더 높은 권한을 가지는 것을 방지합니다.
Kubewarden 정책은 Artifact Hub에서 찾을 수 있으며, 이곳은 쿠버네티스 관련 거의 모든 것을 찾을 수 있는 장소입니다.
artifact hub
사용자는 Kubewarden을 사용하여 사용자 정의 정책 모듈을 개발하고 적용할 수 있습니다. 예를 들어, 특정 크기의 SQL 클레임만을 허용하는 사용자 정의 정책을 만들 수 있습니다.
사용자 정의 정책 생성 방법
정책 요구 사항 정의: 먼저, 이 정책이 해결하려는 문제를 정의합니다. 예를 들어, 클러스터에서 너무 큰 SQL 데이터베이스가 생성되는 것을 방지하고자 할 수 있습니다. 이를 위해 'small', 'medium', 'large'와 같은 특정 크기만을 허용하고자 하는 요구 사항을 정의합니다.
정책 로직 개발: 다음으로, 이 요구 사항을 구현하는 로직을 개발합니다. 이 과정에서는 Kubewarden 정책을 구현할 수 있는 프로그래밍 언어(예: Rust, Go 등)를 사용하여, SQL 클레임의 크기를 검사하고, 허용된 크기에 맞지 않는 클레임을 거부하는 코드를 작성합니다.
WASM으로 컴파일: 개발한 정책 로직을 WebAssembly(WASM)로 컴파일합니다. WASM은 다양한 환경에서 실행될 수 있는 저수준 바이너리 포맷입니다. Kubewarden은 WASM 형식의 정책을 실행합니다.
정책 모듈 배포: 컴파일된 정책 모듈을 컨테이너 이미지로 패키징하고, Docker 레지스트리(예: Docker Hub, GHCR 등)에 배포합니다.
Kubewarden 정책 설정: Kubewarden 정책을 쿠버네티스 클러스터에 적용합니다. 이때 정책 모듈의 위치와 해당 정책이 적용될 리소스 및 조건을 지정하는 YAML 파일을 작성하고 적용합니다.
이 예시에서, 정책은 **sqlclaims**라는 커스텀 리소스에 적용되며, 생성 또는 업데이트 시 'small', 'medium', 'large'라는 크기 제한을 강제합니다. 이를 통해 쿠버네티스 클러스터 내에서 자원 사용을 효과적으로 관리하고, 과도한 리소스 사용을 방지할 수 있습니다.
Kubewarden을 사용하여 사용자 정의 정책 모듈을 개발하고 적용하는 예시로, "특정 크기의 SQL 클레임만을 허용하는 정책"을 들 수 있습니다. 이런 종류의 정책은 쿠버네티스 클러스터에서 SQL 데이터베이스 리소스의 크기를 제한하는 데 사용될 수 있습니다. 여기에는 몇 가지 주요 단계가 있습니다:
Kubewarden의 장점 중 하나는 거의 모든 언어(WASM으로 컴파일될 수 있어야 함)로 정책을 작성할 수 있다는 것이며, 이는 다른 정책 도구와 구별되는 주요 특징입니다.
Kubewarden의 단점으로는 새 정책을 추가할 때마다 정책 서버가 재시작되어야 한다는 점과 쿠버네티스 표준을 따르지 않아 이벤트가 발생하지 않는다는 점이 있습니다.
이벤트 미발생 예시
쿠버네티스 클러스터에서 '파드 메모리 제한' 정책이 위반되어 파드 생성이 거부되었다고 가정해봅시다.
쿠버네티스 표준을 따르는 시스템에서는 이러한 거부 사건이 '이벤트'로 기록되고, 시스템 관리자나 다른 애플리케이션에서 이를 감지할 수 있습니다.
하지만 Kubewarden은 이러한 이벤트를 생성하지 않기 때문에, 관리자나 다른 시스템이 이러한 중요한 정보를 즉시 알 수 없을 수 있습니다.
쿠버네티스에서는 보통 중요한 변화나 상태 변경 시 '이벤트'를 발생시켜 사용자나 다른 시스템 요소에 알립니다.하지만, Kubewarden은 쿠버네티스 표준 이벤트 생성을 지원하지 않아 이러한 알림이 발생하지 않습니다.
Backstage는 CNCF의 인기있는 프로젝트 중 하나로, UI를 제공하는 도구의 기본이 될 수 있지만, 최종 사용자에게 직접 사용되기에는 복잡하고 유지 관리가 어렵.
Port는 현재 사용 가능한 최고의 도구로 평가되며, Kubernetes와 친화적으로 만들어야 할 작업이 있지만, SaaS로만 사용 가능하고 오픈소스가 아니라는 단점이 있음에도 불구하고 추천
서비스 카탈로그(Service Catalog)는 조직 내에서 사용되는 서비스, 애플리케이션, 리소스들의 목록을 관리하고, 사용자가 이들에 접근하고 활용할 수 있도록 도와주는 도구나 시스템을 의미합니다. 이러한 카탈로그는 IT 서비스 관리(ITSM)의 중요한 부분이며, 개발자, IT 전문가, 그리고 다른 사용자들이 필요한 서비스를 쉽게 찾고, 이해하며, 사용할 수 있도록 합니다.
Backstage:
개발자가 서비스를 더 빠르고 효율적으로 찾고, 사용하며, 관리할 수 있도록 도와주는 통합 개발 환경(IDE)입니다.
기업이나 조직의 서비스, 소프트웨어 컴포넌트, 인프라 등을 한 곳에서 관리할 수 있도록 합니다.
사용자 정의가 가능하며, 다양한 플러그인과의 통합을 지원합니다.
Port:
Backstage와 유사한 기능을 제공하지만, 사용자에게 더 친숙하고 쉬운 인터페이스를 제공하는 것을 목표로 합니다.
SaaS(서비스로서의 소프트웨어) 형태로 제공되며, 오픈소스가 아닌 것이 특징입니다.
Kubernetes와의 통합 및 호환성에 중점을 두고 있으며, 쿠버네티스 클러스터에서 실행되는 서비스 관리에 특화되어 있습니다.
Dagger는 새로운 도구로, 어디서나 실행될 수 있는 파이프라인을 정의할 수 있으며, 다양한 언어로 정의 가능.
컨테이너 기반의 파이프라인 도구. 벤더 종속성 피함
4. Observability -Pixie, groundcover
Grafana Cloud가 전체 솔루션으로서 강조됨. Pixie는 혁신적인 접근 방식을 제공.
결국 옵저버빌리티에는 loki, prometheus, victoria metircs, jaeger, tempo, alertmanager, komodor등 여러가지 도구들을 조합해서 사용해야하는데 이런 여러가지 솔루션을 종합적으로 제공하는 Pixie나 groundcover를 추천한다.
관리형 데이터베이스 서비스 사용을 권장, PostgreSQL에 특화된 Cloud Native PG (CMPG)와 Atlas Operator를 추천함
CMPG (Cloud Native PostgreSQL):
CMPG는 PostgreSQL 데이터베이스를 Kubernetes 환경에서 관리하고 운영하기 위한 솔루션입니다.
Kubernetes 네이티브 방식을 채택하여, 데이터베이스 관리를 Kubernetes 클러스터와 일관성 있게 통합합니다. 이는 Kubernetes의 자동화, 확장성, 복원력 등의 장점을 데이터베이스 관리에도 적용할 수 있게 합니다.
PostgreSQL에 특화되어 있어, 이 데이터베이스 시스템을 사용하는 조직에게 특히 유용합니다.
Kubernetes 환경에서의 운영을 간소화하고, 더 효율적인 관리 및 자동화 기능을 제공하는 것이 주된 장점입니다.
Atlas Operator:
Atlas Operator는 MongoDB Atlas와의 통합을 위한 Kubernetes 오퍼레이터입니다.
MongoDB Atlas는 클라우드에서 MongoDB 데이터베이스를 관리하는 서비스로, 자동화된 백업, 확장성, 보안 기능을 제공합니다.
Atlas Operator를 사용하면 Kubernetes 환경 내에서 MongoDB Atlas 리소스를 보다 쉽게 관리하고, Kubernetes 애플리케이션과 MongoDB Atlas 사이의 통합을 간편하게 구성할 수 있습니다.
이러한 통합은 Kubernetes 클러스터의 리소스 관리와 데이터베이스 서비스 관리를 하나의 플랫폼에서 할 수 있게 해, 개발 및 운영 효율성을 높입니다.
6. Infrastructure and Service Management - k8s
Ansible, Terraform, Pulumi 등이 언급되지만, 최종 선택은 Kubernetes 자체임. Kubernetes는 컨테이너 관리뿐만 아니라 다양한 리소스 관리를 위한 플랫폼으로 강조됨
7. Security - KubeScape, Teller
KubeScape는 Kubernetes 클러스터의 보안을 전반적으로 평가하고 개선할 수 있는 능력을 제공합니다. 이는 클라우드 네이티브 환경의 복잡성을 고려할 때 매우 중요한 기능입니다. 자동화된 보안 평가는 클러스터의 보안 상태를 지속적으로 모니터링하고 개선하는 데 큰 도움이 됩니다.
Teller는 민감한 데이터의 관리와 보안을 강화하는 데 중점을 두고 있으며, 특히 개발과 운영 환경에서의 비밀 관리에 있어서 중요한 역할을 합니다. 코드 내에 민감한 데이터를 하드코딩하는 위험을 줄이고, 보안을 강화하는 동시에 개발자의 작업 편의성을 높여줍니다.
KubeScape:
KubeScape는 Kubernetes 환경을 위한 보안 검사 도구입니다.
이 도구는 Kubernetes 클러스터의 구성과 배포된 애플리케이션을 분석하여, 보안 취약점과 비효율적인 구성을 식별합니다.
KubeScape는 CNCF의 보안 벤치마크와 산업 표준에 따라 Kubernetes 환경을 평가합니다. 이를 통해 보안 위험을 줄이고, 클러스터의 보안 상태를 개선하는 데 도움을 줍니다.
자동화된 보안 검사를 통해 개발 및 운영 과정에서의 보안 관리를 간소화하고 효율적으로 만듭니다.
Teller:
Teller는 애플리케이션과 개발 환경에서 비밀번호, API 키, 인증서 등과 같은 민감한 데이터를 안전하게 관리하기 위한 도구입니다.
이 도구는 다양한 비밀 관리 시스템과 통합되며, 이러한 민감한 데이터를 안전하게 가져오고, 관리할 수 있도록 합니다.
개발자들이 코드 내에 민감한 정보를 하드코딩하지 않고도, 필요한 시점에 안전하게 접근할 수 있게 해줍니다.
CI/CD 파이프라인, 개발자의 로컬 환경, 서버 등 다양한 환경에서의 비밀 관리를 지원합니다.
8. Networking - Cilium, Gateway API
서비스 메시 도구들과 함께 Cilium이 중요한 네트워킹 솔루션이다. Cilium은 Kubernetes 네트워킹의 표준이며, eBPF를 기반으로 확장성을 제공함.
Gateway API는 Kubernetes의 Ingress 규격을 대체할 것으로 예상됨
9. Miscellaneous - Charm
Charm은 단일 도구가 아니라 터미널 사용 경험을 개선하기 위한 다양한 도구와 라이브러리의 세트임. 터미널 사용자에게 유용할 것
이걸 도커 구축된 폐쇄망 환경에다가 docker load 로 서버에다가 이미지 정상적으로 넣었는데도 docker run 하면
docker error error contacting notary server dial tcp
위와같은 에러가 발생한다.
이는 docker content tust 설정일 때문일 수 있따.
DOCKER_CONTENT_TRUST 기능
활성화 (DOCKER_CONTENT_TRUST=1): 이 모드에서 Docker는 이미지를 풀(pull)하거나 푸시(push)할 때 서명된 이미지만을 사용합니다. 이미지가 서명되었다는 것은 해당 이미지가 신뢰할 수 있는 소스에서 생성되었으며 변경되지 않았음을 보증합니다. 이를 통해 사용자는 이미지의 출처와 무결성을 확인할 수 있습니다.
비활성화 (DOCKER_CONTENT_TRUST=0): 이 설정에서는 Docker가 서명되지 않은 이미지도 풀하거나 푸시할 수 있습니다. 이는 폐쇄망과 같은 특정 환경에서 필요할 수 있으며, 이미지 출처에 대한 검증이 덜 중요한 경우에 유용합니다.
IDP의 핵심은 사용자의 필요에 맞춘 서비스를 제공하는 것입니다. 예를 들어, AWS의 경우 사용자는 EC2 인스턴스의 크기와 운영 체제를 선택하지만, AWS는 인스턴스의 안정적인 운영을 책임집니다. 이는 각 사용자가 자신의 역할에 집중할 수 있게 하며, 전반적인 효율성을 높입니다.
3. 역할 분담과 책임의 중요성
IDP에서는 서비스 제공자와 사용자 간의 역할 분담이 중요합니다. 서비스 제공자는 시스템의 기술적 측면을 관리하는 반면, 사용자는 제공된 서비스를 효과적으로 활용해야 합니다. 이러한 분담은 명확한 책임 소재와 효율적인 작업 흐름을 보장합니다.
4. 보안과 테스트 전략
보안은 IDP에서 중요한 부분입니다. 서비스 제공자는 시스템의 보안을 유지하는 책임이 있으며, 사용자는 자신의 부분에 대한 보안을 담당합니다. 또한, 효과적인 테스트 전략은 시스템의 안정성을 보장하는 데 중요합니다.
5. 결론: IDP의 성공적인 구축을 위한 전략
IDP의 성공은 사용자 중심의 서비스 디자인과 명확한 역할 분담에 달려 있습니다. 기술적 전문성과 사용자 경험을 모두 고려한 접근 방식이 필요합니다.
1.
예를 들어, 아마존의 배송 옵션에서는 표준 배송이나 특급 배송을 선택하는 단순한 질문과 함께 추가적인 설정으로 배송 시간을 선택할 수 있습니다. 그러나 고객은 배송 방법(트럭, 비행기, 배 등)이나 구체적인 경로 등에 대해 걱정할 필요가 없습니다. 이는 서비스가 중요한 선택사항에 초점을 맞추고, 불필요한 세부사항은 숨김으로써 사용자 경험을 단순화한다는 것을 보여줍니다.
아마존과 고객 간의 계약은 고객이 배송 유형을 선택하고 주소를 확인하는 것에 기반합니다. 아마존은 약속된 목적지와 시간에 패키지를 배달할 책임이 있습니다. 고객은 배송 방법에 대해 걱정할 필요가 없으며, 아마존은 고객이 제공한 정보가 정확하다고 가정합니다. 이는 서비스가 사용자의 필요에 맞춰 구성되어야 함을 보여줍니다.
서비스 제공자가 전문가인 영역에서 추상화를 생성하여 다른 사람들이 쉽게 이용할 수 있도록 해야 한다고 설명합니다. 예를 들어, 어떤 사용자가 쿠버네티스에서 실행되는 애플리케이션의 인스턴스를 생성한다면, 해당 서비스의 역할은 사용자가 만든 추상화 인스턴스로부터 하위 수준의 리소스를 생성하는 것입니다. 이는 애플리케이션, 데이터베이스, 클러스터 등 다양한 서비스에 적용될 수 있습니다.
이 부분에서는 서비스 제공자가 사용자의 필요에 맞춰 설계된 서비스나 추상화를 통해 하위 수준의 리소스를 생성하고 관리하는 방법을 설명합니다. 이러한 방식으로 서비스를 구축하면 소프트웨어 개발 생명주기(SDLC)의 첫 번째 문제가 해결됩니다. 또한, 각자의 역할에 따라 단위 테스트를 수행하는 것이 쉬워집니다. 예를 들어, 서비스 제공자로서 제공하는 서비스가 올바르게 작동하는 것을 보장하는 것이 내 역할이 됩니다.
이 부분에서는 서비스 제공자가 자신이 제공하는 서비스가 예상대로 작동하는지 테스트하는 역할에 대해 설명합니다. 예를 들어 AWS의 경우, EC2 인스턴스 뒤의 하이퍼바이저가 예상대로 작동하는지 확인합니다. 그러나 EC2 인스턴스의 크기 선택 같은 사용자의 구체적인 요구사항은 그들의 책임이 아닙니다. 그들의 역할은 허용된 모든 인스턴스 유형이 생성되고 예상대로 작동하는 것을 보장하는 것입니다. 반면에, 사용자로서 내 역할은 내가 선택한 사양이 내 요구에 맞는지를 확인하는 것입니다.
단위 테스트와 그 결과를 정의하고 관찰하는 것이 추상화의 범위에 제한되기 때문에 쉽다고 설명합니다. 이러한 정보는 Backstage와 같은 UI에 전송되어야 하며, 서비스 제공자가 관리하는 부분은 이미 사용하는 도구들에 의해 커버되고 있습니다. 결과적으로, UI의 범위는 축소되며, 모든 것을 한 곳에서 관리하는 '하나의 창'으로 사용하는 것은 시간 낭비가 될 수 있습니다. 이미 각자가 익숙한 도구들을 사용하고 있기 때문입니다.
UI가 각 전문 분야에 맞춰진 특정 도구가 아니라, 전문 지식이 없는 사람들을 위한 단일 창으로 변모하고 있음을 설명합니다. 예를 들어, 데이터베이스 관리자에게는 특정 데이터베이스 서버를 관리하는 데 도움이 되는 도구들이 있습니다. 새로운 UI는 사용자들에게 그들이 직접적으로 관심을 가질 정보의 일부만을 제공함으로써 가시성을 제공합니다. 이는 아마존 배송 예시로 돌아가 보면, 고객이 배송에 대해 관심을 가지는 부분만을 보여주는 것과 유사합니다.
이 부분에서는 아마존 배송 추적을 예로 들어, 고객이 필요로 하는 정보를 제공하는 방식을 설명합니다. 고객은 패키지가 배송되었는지, 현재 위치가 어디인지만 확인할 수 있습니다. 이는 아마존이 가진 데이터의 일부에 불과합니다. 배송 업체는 패키지의 QR 코드, 운송 방법, 트럭 운전사 등 더 많은 정보를 볼 수 있습니다. 보안 분야에서는 전통적으로 보안 전문가가 애플리케이션 개발자에게 위협 요소를 해결하도록 위임하는 방식이 있었으나, 이는 종종 효과적이지 않았습니다.
많은 보안 문제는 운영 체제나 기본 이미지의 업그레이드, 운영 체제 라이브러리의 변경 등으로 해결될 수 있습니다. 그러나 개발자가 선택하지 않았거나 무작위로 선택한 요소를 수정하는 것은 비현실적입니다. 그러나 서비스를 제공하고 이를 애플리케이션 개발자들이 소비하는 방향으로 나아가면, 누가 어떤 보안 위협을 해결해야 하는지 명확한 구분이 생깁니다.
보안 책임의 분리에 대해 설명합니다. 개발자가 직접 코드에 포함한 라이브러리로 인해 발생한 보안 취약점은 개발자가 수정해야 합니다. 반면, 다른 사람이 제공한 서비스를 사용하여 발생한 문제는 그 서비스 제공자가 책임져야 합니다. 예를 들어, 데이터베이스 관리자가 서비스로 데이터베이스를 생성했고, 개발자가 그 인스턴스를 실행하는 경우, 발생하는 문제는 관리자의 책임이 될 수 있습니다. 이러한 구분은 보안 문제 해결에 있어 중요한 역할을 합니다.
이 부분에서는 서비스 사용자가 서비스 제공자의 책임 하에 있는 취약점이 있는 데이터베이스 인스턴스를 생성했을 수 있는 상황을 설명합니다. 예를 들어, 이미 알려진 취약점이 있는 PostgreSQL 13 데이터베이스를 사용하는 경우, 데이터베이스 관리자는 그러한 선택을 방지하기 위한 정책을 설정했어야 하며, 대신 안전한 버전(예: PostgreSQL 14)을 사용하도록 권장했어야 합니다. 서비스 제공자는 사용자가 잘못된 선택을 하지 않도록 지원하는 정책을 마련해야 합니다.
서비스 제공자는 서비스 사용으로 생성된 리소스가 안전하도록 보장하는 책임이 있으며, 서비스 사용자는 제공된 추상화 범위 내에서 안전한 선택을 해야 합니다. 서비스 제공자는 서비스 인스턴스에서 생성된 하위 수준 리소스를 스캔해야 하며, 서비스 사용자는 인스턴스 자체를 스캔해야 합니다.
사용자는 API 호출이 정확하고 요청된 정보가 원하는 상태와 일치하는지 확인해야 합니다. API 호출 이후의 과정, 즉 컨트롤 플레인 내에서 발생하는 모든 일은 서비스 제공자의 책임으로, 서비스가 제대로 작동하는지 보장하기 위해 테스트해야 합니다. 또한, 관찰 가능성은 서비스 제공자와 사용자가 사용하는 데이터 및 도구 사이의 가장 큰 차이점 중 하나일 수 있습니다.
이 부분에서는 서비스의 추상화에 포함되지 않는 정보를 최종 사용자에게 노출하는 것은 무의미하다고 설명합니다. 예를 들어, 사용자가 데이터베이스에 할당할 메모리 양을 지정할 수 있다면, 해당 메모리 정보는 최종 사용자에게 제공되는 관찰 가능성 도구의 그래프 중 하나로 제공되어야 합니다. 반면, 메모리 사양이 추상화의 일부가 아니라면, 서비스 자체에서 필요한 만큼의 메모리를 할당하는 것으로 간주하고, 이 정보를 최종 사용자의 관찰 가능성에 추가하는 것은 혼란을 증가시킬 수 있습니다.
이 부분에서는 내부 개발자 플랫폼(IDP)을 구축하는 것이 어렵다고 설명합니다. 단순히 기존 도구와 프로세스 위에 UI를 구축하는 것만으로는 충분하지 않으며, IDP는 핵심 역량을 벗어난 작업을 수행할 수 있도록 최종 사용자를 지원하는 서비스의 집합입니다. IDP는 단일 팀이 아닌, 여러 팀의 협력을 통해 구축되어야 하며, 이는 각 사용자의 필요에 부합하는 서비스를 제공하는 데 중점을 둡니다.
이 부분에서는 내부 개발자 플랫폼(IDP)을 효과적으로 구축하기 위한 전략에 대해 설명합니다. 데이터베이스, 인프라, 애플리케이션 아키텍처 등 특정 분야의 전문가들이 IDP를 구성하는 서비스를 구축합니다. 각 팀이 자동화를 통해 자급자족하고 독립적으로 작동하려면, 그들이 필요한 것을 정의하고 애플리케이션 및 기반 인프라의 상태를 관찰할 수 있어야 합니다. 단순한 자동화만으로는 이러한 목표를 달성할 수 없습니다.
서버리스란 개발자들이 애플리케이션을 만들 때 서버를 직접 구축하고 관리하는 대신에 클라우드 공급자(예: AWS, Azure, Google Cloud)가 제공하는 서버리스 서비스를 사용하는 것을 의미합니다. 이는 개발자들이 애플리케이션 코드에 집중할 수 있도록 도와주며, 서버 관리와 같은 인프라 작업을 간소화합니다.
그러나 이 방법을 선택하면 약간의 제한사항이 발생할 수 있습니다. 예를 들어, 클라우드 공급자가 제공하는 서비스의 방식과 기능을 따라야 하기 때문에 개발자가 특정한 제한 사항을 갖게 될 수 있습니다. 이것이 바로 "벤더 락인" 또는 "공급자 종속성"이라고 불리는 현상입니다.
간단히 말해서, 서버리스를 사용하면 편리하고 빠른 개발이 가능하지만, 클라우드 공급자가 정한 규칙과 제한사항을 따라야 하므로 개발자가 자유롭게 원하는 대로 모든 것을 조절하는 것이 어려울 수 있습니다. 따라서 이러한 제한을 고려하여 개발 방향을 결정해야 합니다.
OpenFunction은 서버리스 컴퓨팅 플랫폼으로, 사용자가 애플리케이션의 비즈니스 로직에 집중할 수 있게 해주는 것을 목표로 합니다. 즉, 사용자는 기반 인프라나 운영 체제, 하드웨어 등에 대해 걱정할 필요 없이 애플리케이션 개발에만 집중할 수 있습니다.
그러나 실제로 OpenFunction을 사용하려면, 사용자가 스스로 이 플랫폼을 설정하고 유지 관리해야 합니다. 이것은 Kubernetes 클러스터의 설정 및 유지 관리, OpenFunction이 통합하는 다양한 구성 요소(예: 빌드 도구, 실행 환경)의 유지 관리, 그리고 OpenFunction 자체의 유지 관리를 포함합니다.
간단히 말해서, OpenFunction은 개발자가 애플리케이션 개발에만 집중할 수 있게 도와주는 플랫폼이지만, 이 플랫폼 자체를 운영하고 유지 관리하기 위해서는 기술적인 지식과 추가적인 노력이 필요하다는 것입니다. 따라서 비전공자나 기술적 지식이 부족한 사람이 OpenFunction을 효과적으로 사용하려면, 기술적인 부분을 관리할 수 있는 전문가의 도움이 필요할 수 있습니다.
강점으로는 서버리스 컴퓨팅의 이점, 다양한 도구와의 통합
단점으로는 불친절한 문서화, 특정 기술에 대한 깊은 이해가 필요하다는 점, 빌더가 자주 유지되지 않는다는 점
실제 사용 사례: 함수 생성, HTTP 트리거, 데이터베이스 연동, 스케일링 테스트 등을 포함합니다.
로컬 소스 코드에서 함수를 빌드 방법
컨테이너 이미지로 소스 코드 패키징: 로컬에 있는 소스 코드를 컨테이너 이미지로 패키징하고, 이 이미지를 컨테이너 레지스트리에 푸시합니다.
Dockerfile 사용: 소스 코드가 'samples' 디렉토리에 있다고 가정할 때, 아래와 같은 Dockerfile을 사용하여 소스 코드 번들 이미지를 빌드할 수 있습니다
dockerfileCopy code
FROM scratch
WORKDIR /
COPY samples samples/
이미지 빌드 및 푸시: 다음 명령어를 사용하여 소스 코드 번들 이미지를 빌드하고 푸시합니다.
Cloud Native Buildpacks 사용: OpenFunction은 Cloud Native Buildpacks를 사용하여 Dockerfile 생성 없이 함수 이미지를 빌드하는 것을 지원합니다. 이는 Serverless Applications을 Dockerfile과 함께 빌드할 때도 사용될 수 있습니다.
Build 섹션 정의를 통한 함수 빌드: 사용자는 Git 저장소의 소스 코드나 로컬에 저장된 소스 코드에서 함수나 애플리케이션을 빌드할 수 있습니다. Function 정의에 빌드 섹션을 추가하면, 서빙 섹션도 정의되어 있다면 빌드가 완료되자마자 함수가 시작됩니다.
Pack CLI 사용: 디버그 목적이나 오프라인 환경에서는 로컬 소스 코드에서 직접 함수 이미지를 빌드하는 것이 필요할 수 있습니다. 이를 위해 Pack CLI를 사용할 수 있습니다. Pack는 Cloud Native Buildpacks 프로젝트에 의해 유지되며 빌드팩을 사용하여 애플리케이션을 빌드하는 기능을 제공합니다.
OpenFunction Builders: Cloud Native Buildpacks를 사용하여 함수 이미지를 빌드하려면 빌더 이미지가 필요합니다. OpenFunction 커뮤니티에서는 여러 인기 언어에 대한 빌더를 제공하고 있습니다.
git 리포지토리의 소스 코드에서 함수 빌드하기
아래와 같이 함수 정의에 빌드 섹션을 추가하기만 하면 함수 이미지를 빌드할 수 있습니다. 서빙 섹션이 함께 정의되어 있으면 빌드가 완료되는 즉시 함수가 실행됩니다.
apiVersion: core.openfunction.io/v1beta2
kind: Function
metadata:
name: logs-async-handler
spec:
version: "v2.0.0"
image: openfunctiondev/logs-async-handler:v1
imageCredentials:
name: push-secret
build:
builder: openfunction/builder-go:latest
env:
FUNC_NAME: "LogsHandler"
FUNC_CLEAR_SOURCE: "true"
## Customize functions framework version, valid for functions-framework-go for now
## Usually you needn't to do so because the builder will ship with the latest functions-framework
# FUNC_FRAMEWORK_VERSION: "v0.4.0"
## Use FUNC_GOPROXY to set the goproxy
# FUNC_GOPROXY: "https://goproxy.cn"
srcRepo:
url: "https://github.com/OpenFunction/samples.git"
sourceSubPath: "functions/async/logs-handler-function/"
revision: "main"
이외에도 아래와 같은 방법으로 빌드가 가능하다.
Pack CLI 사용: 디버그 목적이나 오프라인 환경에서는 로컬 소스 코드에서 직접 함수 이미지를 빌드하는 것이 필요할 수 있습니다. 이를 위해 Pack CLI를 사용할 수 있습니다. Pack는 Cloud Native Buildpacks 프로젝트에 의해 유지되며 빌드팩을 사용하여 애플리케이션을 빌드하는 기능을 제공합니다.
OpenFunction Builders: Cloud Native Buildpacks를 사용하여 함수 이미지를 빌드하려면 빌더 이미지가 필요합니다. OpenFunction 커뮤니티에서는 여러 인기 언어에 대한 빌더를 제공하고 있습니다.
Overview OpenFunction is a cloud-native open source FaaS (Function as a Service) platform aiming to let you focus on your business logic without having to maintain the underlying runtime environment and infrastructure. You can generate event-driven and dyn
책과 책갈피 예시: 책은 여러 페이지로 구성되어 있으며, 각 페이지에는 다양한 내용이 담겨 있습니다. 책갈피는 책을 읽다가 멈춘 특정 페이지를 표시하여, 다음에 책을 읽을 때 어디서부터 시작해야 하는지를 알려줍니다. Terraform과 State 예시: Terraform은 여러 리소스(서버, 데이터베이스 등)로 구성되어 있으며, 각 리소스에는 다양한 설정이 담겨 있습니다. State는 Terraform으로 인프라를 구성하다가 현재 어떤 리소스가 어떤 상태인지를 저장하여, 다음에 인프라를 변경할 때 어떤 리소스를 어떻게 변경해야 하는지를 알려줍니다. 상세 설명: 책갈피 없이 책 읽기: 책갈피가 없다면, 매번 책을 읽을 때마다 어디까지 읽었는지를 기억하거나 찾아야 합니다. State 없이 Terraform 사용하기: State가 없다면, Terraform은 매번 인프라의 현재 상태를 알 수 없어서, 어떤 리소스를 생성, 수정, 삭제해야 하는지를 판단하기 어렵습니다.
Serial을 기준으로 State Backup을 관리한다.
위와 같이 테라폼 내용을 수정/배포하면 Serial이 변경되는것을 확인할 수 있다.
팀 단위로 테라폼을 운영할때는 팀 모두가 동일한 state를 이용해야 하기 때문에 공유 위치에 state파일을 저장해야한다.
워크스페이스를 분리하여 운영할수도 있다.
개발, 테스트, 스테이징, 운영등의 환경을 워크스페이스로 분리하면 리스크를 관리하고 리소스를 최적화, 개발 효율성도 높일수 있을것이다. 또한 배포 관리도 가능할것이고.
위와같이 dev 라는 workspace에서는 Dev.txt 파일이 생성된것을 볼수있다.
그럼 다시
prod workspace에서는 prod.txt 가 생성된것을 확인할 수 있다.
2. 모듈
모듈이란 재사용 가능한 코드블록으로 여러 리소스와 설정을 그룹화하여 관리가 가능하다. 코드의 재사용성과 관리효율성을 향상시킨다.
데이터소스는 테라폼이 사용자가 원하는 인프라 상태를 설정하기 위해 필요한 정보를 "인터넷에서 검색하는 키워드"와 같다고 볼 수 있습니다.
인프라 설정을 위한 정보: 테라폼은 클라우드 서비스나 서버, 네트워크 등 다양한 인프라 자원을 관리합니다. 이런 자원을 설정하려면 예를 들어 서버 크기, 리전, 네트워크 구성 등과 같은 정보가 필요합니다. 데이터소스는 이런 정보를 테라폼에 제공합니다.
외부 데이터의 활용: 데이터소스는 종종 외부 소스에서 정보를 가져올 수 있습니다. 예를 들어, 클라우드 제공업체의 가용 영역 정보나 이미 존재하는 리소스의 상태를 가져오는 데 사용될 수 있습니다.
설정의 유연성: 데이터소스를 사용하면 테라폼 설정을 더 유연하게 만들 수 있습니다. 즉, 특정 리전, 가용 영역, 또는 네트워크 구성을 하드 코딩하지 않고 데이터소스를 통해 동적으로 설정할 수 있습니다.
간단히 말하면, 데이터소스는 테라폼이 인프라 자원을 관리할 때 필요한 정보를 효과적으로 확보하는 방법으로 생각할 수 있으며, 이를 통해 테라폼 설정을 더 쉽게 관리하고 유연하게 만들 수 있습니다.
데이터 소스 블록의 구조: 데이터 소스 블록은 data 키워드로 시작하며, 이후에는 데이터 소스 유형을 정의합니다. 데이터 소스 유형은 프로바이더 이름과 해당 프로바이더에서 제공하는 특정 데이터 소스 유형을 나타내며 밑줄 (_)로 구분됩니다. 데이터 소스 유형을 정의한 후에는 데이터 소스 인스턴스에 대한 고유한 이름을 지정합니다. 이름은 리소스의 이름과 마찬가지로 중복되지 않아야 하며, 데이터 소스의 인스턴스를 식별하는 데 사용됩니다.
예를 들어, local 프로바이더에서 제공하는 파일 데이터 소스를 정의한 코드는 다음과 같습니다:
data "local_file" "example_file" {
filename = "${path.module}/abc.txt"
}
이 코드에서 local_file은 데이터 소스 유형을 나타내고, example_file은 데이터 소스 인스턴스의 고유한 이름입니다.
데이터 소스 구성 인수: 데이터 소스 블록 내부의 중괄호 { } 안에는 데이터 소스 유형에 대한 구성 인수를 선언합니다. 이러한 구성 인수는 데이터 소스가 작동하는 데 필요한 정보를 제공합니다. 구성 인수의 이름과 값을 설정하여 데이터 소스를 구성합니다. 각 데이터 소스 유형은 지원하는 구성 인수가 다를 수 있으며, 해당 데이터 소스의 문서에서 확인할 수 있습니다.
메타 인수: 데이터 소스 블록에서는 몇 가지 메타 인수를 사용할 수 있습니다. 이러한 메타 인수를 사용하여 데이터 소스의 동작을 제어하거나 관리할 수 있습니다.
depends_on: 이 메타 인수를 사용하여 종속성을 선언할 수 있습니다. 종속성을 정의하면 데이터 소스가 의존하는 다른 리소스나 데이터 소스가 먼저 생성되도록 제어할 수 있습니다.
count: 이 메타 인수를 사용하여 데이터 소스를 여러 번 생성하고 동일한 데이터 소스 유형을 여러 번 사용할 수 있습니다. 예를 들어, 여러 파일에 대한 데이터 소스를 생성할 때 유용합니다.
count: count 메타 인수는 variable "file_paths"에 정의된 파일 경로 목록의 길이에 따라 데이터 소스 인스턴스를 여러 번 생성합니다. 각 데이터 소스 인스턴스는 다른 파일을 대상으로 하며, count.index를 사용하여 파일 경로를 선택합니다.
for_each: for_each 메타 인수를 사용하여 variable "file_data"에 정의된 파일 데이터 맵을 기반으로 데이터 소스 인스턴스를 생성합니다. 각 데이터 소스 인스턴스는 다른 파일을 대상으로 합니다. each.key와 each.value를 사용하여 파일 이름과 파일 경로를 선택합니다.
입력 변수 (Input Variables)는 Terraform 코드 내에서 사용되며, 인프라 구성에 필요한 속성 값을 정의하는 데 사용됩니다. 이를 통해 코드를 변경하지 않고 여러 인프라를 생성할 수 있습니다.
변수를 정의하는 방법과 변수 유형, 유효성 검사 및 민감한 변수 처리에 대한 내용을 살펴보겠습니다.
1. 변수 선언 방식
변수는 variable 블록으로정의됩니다. 이블록은다음과같은구조를가집니다:
variable "<이름>" {
<인수> = <값>
}
여기서 <이름>은 변수의 고유한 이름이며, 다른 코드에서 변수를 참조할 때 사용됩니다. 변수 블록 내에서는 변수의 데이터 유형, 설명, 기본값 등을 설정할 수 있습니다.
변수 정의 시 사용 가능한 메타인수
default : 변수 값을 전달하는 여러 가지 방법을 지정하지 않으면 기본값이 전달됨, 기본값이 없으면 대화식으로 사용자에게 변수에 대한 정보를 물어봄
variable "region" {
type = string
default = "us-east-1"
}
type : 변수에 허용되는 값 유형 정의, string number bool list map set object tuple 와 유형을 지정하지 않으면 any 유형으로 간주
variable "instance_type" {
type = string
default = "t2.micro"
}
description : 입력 변수의 설명
variable "subnet_id" {
type = string
description = "The ID of the subnet where the resource will be deployed."
}
validation : 변수 선언의 제약조건을 추가해 유효성 검사 규칙을 정의
variable "port" {
type = number
validation {
condition = var.port >= 0 && var.port <= 65535
error_message = "Port number must be between 0 and 65535."
}
}
sensitive : 민감한 변수 값임을 알리고 테라폼의 출력문에서 값 노출을 제한 (암호 등 민감 데이터의 경우)
variable "password" {
type = string
sensitive = true
}
nullable : 변수에 값이 없어도 됨을 지정
variable "optional_variable" {
type = string
nullable = true
}
2. 변수 유형
Terraform에서는 여러 종류의 변수 유형을 지원합니다. 주요 변수 유형은 다음과 같습니다:
string: 글자 유형
number: 숫자 유형
bool: true 또는 false
list: 리스트 형태, 예를 들어 문자열 리스트
map: 키-값 쌍으로 이루어진 맵
set: 중복을 허용하지 않는 집합
object: 복잡한 구조를 가진 객체
tuple: 고정된 크기의 순서가 있는 집합=
변수 우선 순위
[우선순위 수준 1]: 직접 입력 가장 높은 우선순위를 가지며, 테라폼 실행 중에 직접 값을 입력할 수 있습니다.
[우선순위 수준 2]: 변수 블록의 기본값(Default) 변수를 정의할 때 기본값을 설정할 수 있습니다. 이 값은 다른 곳에서 값을 지정하지 않을 때 사용됩니다.
[우선순위 수준 3]: 환경 변수 시스템 환경 변수의 이름이 TF_VAR_로 시작하면 해당 변수 이름으로 값을 설정할 수 있습니다.
[우선순위 수준 4]: terraform.tfvars 파일 terraform.tfvars 파일에 변수 값을 저장할 수 있습니다. 이 파일은 코드와 같은 디렉터리에 있어야 합니다.
[우선순위 수준 5]: *.auto.tfvars 파일 코드와 같은 디렉터리에 있는 .auto.tfvars 확장자를 가진 파일에 변수 값을 저장할 수 있습니다. 파일명의 알파벳 순서로 우선순위가 정해집니다.
[우선순위 수준 6]: *.auto.tfvars.json 파일 코드와 같은 디렉터리에 있는 .auto.tfvars.json 확장자를 가진 JSON 파일에 변수 값을 저장할 수 있습니다. 파일명의 알파벳 순서로 우선순위가 정해집니다.
[우선순위 수준 7]: CLI 실행 시 -var 인수 또는 -var-file 옵션 테라폼 명령어를 실행할 때 -var 옵션을 사용하여 변수 값을 전달할 수 있습니다. 이 옵션으로 변수 값을 지정하면 다른 모든 우선순위를 덮어씁니다. 또한 -var-file 옵션을 사용하여 변수 값이 정의된 파일을 지정할 수도 있습니다.
locals란
**로컬(local)**은 마치 여러분이 노트에 어떤 계산을 해서 그 값을 기억해두는 것과 비슷합니다. 그러면 필요할 때마다 그 값을 다시 불러와 사용할 수 있습니다.
로컬을 사용하는 이유는 여러 번 반복해서 사용하는 값을 효율적으로 다루기 위해서입니다. 예를 들어, 여러 리소스를 만들 때 사용하는 이름이나 설정 값 등을 한 번 정해놓고 필요할 때마다 그 값을 가져와서 사용할 수 있습니다.
로컬은 테라폼 코드 내에서만 사용되며, 사용자나 외부로부터 입력을 받지 않습니다. 코드 내에서 미리 정의되어 있어서 다른 사람이 코드를 읽을 때 무엇을 의미하는지 쉽게 파악할 수 있게 해줍니다.
로컬 값을 사용하기 위해서는 코드 내에서 locals라는 블록을 사용합니다. 그 안에서 로컬 변수의 이름과 그 변수에 할당할 값을 정의합니다.
로컬 값을 참조할 때는 local.<이름> 형식을 사용하며, 다른 테라폼 코드 파일에서도 사용할 수 있습니다. 이렇게 하면 여러 코드 파일 간에 값을 공유하거나 재사용할 수 있습니다.
로컬 값은 코드의 가독성을 높이고 반복 작업을 줄이는 데 도움을 줍니다. 그러나 로컬 값을 과도하게 사용하면 코드를 이해하기 어려워질 수 있으므로 적절하게 활용해야 합니다.
반복문
count : 반복문, 정수 값만큼 리소스나 모듈을 생성
resource "aws_instance" "example" {
count = 3 # 세 개의 EC2 인스턴스 생성
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
위 예제에서는 count를 사용하여 세 개의 EC2 인스턴스를 생성합니다. 각 인스턴스는 동일한 AMI 및 인스턴스 유형을 가지고 있습니다.
위 예제에서는 for_each를 사용하여 var.servers 맵을 기반으로 EC2 인스턴스를 생성합니다. 각 인스턴스는 고유한 AMI 및 이름을 가지고 있습니다.
for_each는 테라폼에서 사용되는 반복문 중 하나로, 이것을 이해하는 데 비유를 들어보겠습니다. 생각해보세요. 여러분이 서로 다른 지역에 있는 친구들과 휴가를 가고 싶다고 상상해보세요. 각 친구마다 서로 다른 여행지와 일정을 가지고 있습니다. 이때 for_each는 여러분이 이런 상황에서 사용할 수 있는 가상의 "여행 일정부표"와 같다고 생각할 수 있습니다. 이 부표에는 여러 친구들의 여행 정보가 기록되어 있습니다. 친구 A: 파리로 5일간 친구 B: 도쿄로 7일간 친구 C: 뉴욕으로 4일간 for_each를 사용하면, 이 "여행 일정부표"를 보고 테라폼이 각 친구에게 해당하는 여행지와 기간에 맞게 여행 예약을 생성할 수 있습니다. 여기서 for_each는 각 친구를 나타내는 항목을 하나씩 가져와서 여행 예약을 만듭니다. 다시 말해, for_each를 사용하면 여러분이 가진 데이터를 기반으로 여러 개의 리소스나 설정을 자동으로 생성할 수 있습니다. 이것은 반복 작업을 자동화하고, 설정을 더 효과적으로 관리하는 데 도움이 됩니다. 그러니까, for_each는 여러분이 가진 여러 데이터를 기반으로 여러 가지 작업을 자동으로 반복 수행하는 도구라고 생각하시면 됩니다.
for : 복합 형식 값의 형태를 변환하는 데 사용 ← for_each와 다름
variable "numbers" {
type = list
default = [1, 2, 3, 4, 5]
}
locals {
squared_numbers = [for num in var.numbers : num * num]
}
위 예제에서는 for를 사용하여 var.numbers 리스트의 각 요소를 제곱한 새로운 리스트를 만듭니다. for는 반복문의 일종으로, 특정 작업을 여러 번 반복할 때 사용됩니다. 이것을 비유하자면, 여러분이 같은 일을 여러 번 반복하는 상황과 비슷합니다. 예를 들어, 여러분이 동일한 메시지를 여러 사람에게 보내야 한다고 상상해보세요. for를 사용하면 메시지 내용을 작성한 후, 그 메시지를 여러 명의 친구나 동료에게 보내는 작업을 반복적으로 수행할 수 있습니다.
반면에, for_each는 데이터를 기반으로 리소스나 설정을 여러 번 생성하는 데 사용됩니다. 비유로 설명하자면, 여러분이 서로 다른 여행 일정을 가진 여러 명의 친구들이 있다고 상상해보세요. 각 친구의 여행 정보는 다르기 때문에, for_each를 사용하여 각각의 여행 일정에 대한 예약을 생성할 수 있습니다.
간단히 말해서, for는 같은 작업을 반복하는 데 사용되고, for_each는 데이터를 기반으로 여러 가지 작업을 반복해서 리소스를 생성하는 데 사용됩니다. 이 둘은 서로 다른 상황에서 사용되며, 각각의 목적에 맞게 선택적으로 테라폼 코드 내에서 사용할 수 있습니다.