본문 바로가기

PYTHON-BACK

#파이썬 24.09.25_AWS CloudFront 실습3+클라우드 서버 내 Docker & Kubernates

728x90

S3사용하기

  • 어제 코드에서 맨 아래 암호키 추가를 하게 되면 로컬사용이 가능한것같다(나는 성공하지 못함..)
import io
import os
import uuid

import boto3
from boto3.s3.transfer import S3UploadFailedError
from botocore.exceptions import ClientError


def do_scenario(s3_resource):
    print("-" * 88)
    print("Welcome to the Amazon S3 getting started demo!")
    print("-" * 88)

    bucket_name = f"doc-example-bucket-{uuid.uuid4()}"
    bucket = s3_resource.Bucket(bucket_name)
    try:
        bucket.create(
            CreateBucketConfiguration={
                "LocationConstraint": s3_resource.meta.client.meta.region_name
            }
        )
        print(f"Created demo bucket named {bucket.name}.")
    except ClientError as err:
        print(f"Tried and failed to create demo bucket {bucket_name}.")
        print(f"\t{err.response['Error']['Code']}:{err.response['Error']['Message']}")
        print(f"\nCan't continue the demo without a bucket!")
        return

    file_name = None
    while file_name is None:
        file_name = input("\nEnter a file you want to upload to your bucket: ")
        if not os.path.exists(file_name):
            print(f"Couldn't find file {file_name}. Are you sure it exists?")
            file_name = None

    obj = bucket.Object(os.path.basename(file_name))
    try:
        obj.upload_file(file_name)
        print(
            f"Uploaded file {file_name} into bucket {bucket.name} with key {obj.key}."
        )
    except S3UploadFailedError as err:
        print(f"Couldn't upload file {file_name} to {bucket.name}.")
        print(f"\t{err}")

    answer = input(f"\nDo you want to download {obj.key} into memory (y/n)? ")
    if answer.lower() == "y":
        data = io.BytesIO()
        try:
            obj.download_fileobj(data)
            data.seek(0)
            print(f"Got your object. Here are the first 20 bytes:\n")
            print(f"\t{data.read(20)}")
        except ClientError as err:
            print(f"Couldn't download {obj.key}.")
            print(
                f"\t{err.response['Error']['Code']}:{err.response['Error']['Message']}"
            )

    answer = input(
        f"\nDo you want to copy {obj.key} to a subfolder in your bucket (y/n)? "
    )
    if answer.lower() == "y":
        dest_obj = bucket.Object(f"demo-folder/{obj.key}")
        try:
            dest_obj.copy({"Bucket": bucket.name, "Key": obj.key})
            print(f"Copied {obj.key} to {dest_obj.key}.")
        except ClientError as err:
            print(f"Couldn't copy {obj.key} to {dest_obj.key}.")
            print(
                f"\t{err.response['Error']['Code']}:{err.response['Error']['Message']}"
            )

    print("\nYour bucket contains the following objects:")
    try:
        for o in bucket.objects.all():
            print(f"\t{o.key}")
    except ClientError as err:
        print(f"Couldn't list the objects in bucket {bucket.name}.")
        print(f"\t{err.response['Error']['Code']}:{err.response['Error']['Message']}")

    answer = input(
        "\nDo you want to delete all of the objects as well as the bucket (y/n)? "
    )
    if answer.lower() == "y":
        try:
            bucket.objects.delete()
            bucket.delete()
            print(f"Emptied and deleted bucket {bucket.name}.\n")
        except ClientError as err:
            print(f"Couldn't empty and delete bucket {bucket.name}.")
            print(
                f"\t{err.response['Error']['Code']}:{err.response['Error']['Message']}"
            )

    print("Thanks for watching!")
    print("-" * 88)


# if __name__ == "__main__":
#     do_scenario(boto3.resource("s3"))

if __name__ == "__main__":

    session = boto3.Session(
        aws_access_key_id = "**********",
        aws_secret_access_key = "*****************************************",
        region_name = "ap-northeast-2"
    )
    do_scenario(session.resource('s3'))
 
  • 암호키랑 리전네임(서울)을 넣어주니까 동작되는 것을 확인 

DynamoDB 사용

- dynamodb에서 테이블을 생성해서 진행(test 라는 테이블)


import boto3

dynamodb = boto3.client('dynamodb')

dynamodb.put_item(
    TableName='YourTableName', # 우리의 경우 test
    Item={
        'pk': {'S': 'id#1'},
        'sk': {'S': 'cart#123'},
        'name': {'S': 'SomeName'},
        'inventory': {'N': '500'},
        # ... more attributes ...
    }
)

 

  • 리소스 인터페이스를 사용하여 항목 삽입하기
- 이번에는 ubuntu에서 nano를 사용해서 에디터를 대신함
- 이번에는 클라이언트가 아닌 테이블 리소스에서 가져와 그 안에 집어 넣는 것으로 진행함
import boto3

dynamodb = boto3.resource('dynamodb')

table = dynamodb.Table('YourTableName') # 우리의 경우 test

table.put_item(
    Item={
        'pk': 'id#1',
        'sk': 'cart#123',
        'name': 'SomeName',
        'inventory': 500,
        # ... more attributes ...
    }
)

  • nano의 경우 ctrl 5를 눌러야 저장이 됨 
  • 위와같이 저장된것을 확인

  • 함께 제공된 및 클래스를 사용하여 일반 JSON과 DynamoDB JSON 간에 변환하기
def dynamo_to_python(dynamo_object: dict) -> dict:
    deserializer = TypeDeserializer()
    return {
        k: deserializer.deserialize(v)
        for k, v in dynamo_object.items()
    }

def python_to_dynamo(python_object: dict) -> dict:
    serializer = TypeSerializer()
    return {
        k: serializer.serialize(v)
        for k, v in python_object.items()
    }

  • 클라이언트 인터페이스를 사용하여 쿼리 수행하기
import boto3

client = boto3.client('dynamodb')

# Construct the query
response = client.query(
    TableName='YourTableName',
    KeyConditionExpression='pk = :pk_val AND begins_with(sk, :sk_val)',
    FilterExpression='#name = :name_val',
    ExpressionAttributeValues={
        ':pk_val': {'S': 'id#1'},
        ':sk_val': {'S': 'cart#'},
        ':name_val': {'S': 'SomeName'},
    },
    ExpressionAttributeNames={
        '#name': 'name',
    }
)
  • 위 내용도 동일하게 nano로 진행


  • 리소스 인터페이스를 사용하여 쿼리 수행하기
import boto3
from boto3.dynamodb.conditions import Key, Attr

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('YourTableName')

response = table.query(
    KeyConditionExpression=Key('pk').eq('id#1') & Key('sk').begins_with('cart#'),
    FilterExpression=Attr('name').eq('SomeName')
)
  • 위 다른것들이랑 형태가 조금 다른것을 확인함
  • 클라이언트 인터페이스를 사용하여 테이블의 대략적인 크기 얻기
import boto3

dynamodb = boto3.client('dynamodb')

response = dynamodb.describe_table(TableName='YourTableName')
size = response['Table']['TableSizeBytes']

print(f"Table size: {size}")
  • 리소스 인터페이스를 사용하여 테이블의 대략적인 크기 얻기
import boto3

dynamodb = boto3.resource('dynamodb')

table = dynamodb.Table('YourTableName')
size = table.table_size_bytes

print(f"Table size: {size}")

 

 


Polly 사용하기

from boto3 import Session
from botocore.exceptions import BotoCoreError, ClientError
from contextlib import closing
import os
import sys
import subprocess
from tempfile import gettempdir

# AWS 자격 증명 파일 (~/.aws/credentials)의 [관리자] 섹션에 정의 된
# 자격 증명 및 영역을 사용하여 클라이언트를 만듦(~/.aws/credentials).
session = Session(profile_name="adminuser")
polly = session.client("polly")

try:
    # 음성 합성 요청
    response = polly.synthesize_speech(Text="Hello world!", OutputFormat="mp3", VoiceId="Joanna")

except (BotoCoreError, ClientError) as error:
    # 서비스는 오류를 반환하고 종료
    print(error)
    sys.exit(-1)

# 응답으로부터 오디오 스트림에 액세스
if "AudioStream" in response:
    # 참고 : 서비스가 병렬 연결 수에 조절되기 때문에 스트림을 닫는 것이 중요함.
    # 여기서는 contextLib.closing을 사용하여 스트림 객체의 닫기 메소드가 명령문의
    # 범위 끝에 자동으로 호출되도록 함.
    with closing(response["AudioStream"]) as stream:
        output = os.path.join(gettempdir(), "speech.mp3")

        try:
        # 바이너리 스트림으로 출력을 쓰기위한 파일 열기
            with open(output, "wb") as file:
                file.write(stream.read())
        except IOError as error:
            # 파일에 쓸 수 없었음. 종료
            print(error)
            sys.exit(-1)

else:
    # 응답에 오디오 데이터가 포함되어 있지 않았음. 종료
    print("Could not stream audio")
    sys.exit(-1)

# 플랫폼의 기본 플레이어를 사용하여 오디오 재생
# 윈도우의 경우
if sys.platform == "win32":
    os.startfile(output)
else:
    # MacOS 및 Linux의 경우(Darwin = Mac, XDG-OPEN = Linux)
    opener = "open" if sys.platform == "darwin" else "xdg-open"
    subprocess.call([opener, output])
  • 리눅스 쪽에서는 재생은 안되지만 파일은 생성됨
  • 권한을 만들어서 진행하는것이 좋아보임

클라우드 서버 내 Docker & Kubernates

컨테이너 기술 보급과 쿠버네티스

가상머신
  • 물리적으로 존재하는 컴퓨터가 아닌, 다른 컴퓨터가 만들어내는 가상의 컴퓨터
  • 호스트 OS에 하이퍼바이저를 설치하고 그 위에 게스트 OS를 작동시키는 형태로 동작
  • 실제 머신의 하드웨어의 기능을 에뮬레이팅함으로써 동작을 지원
    • 에뮬레이션으로만 가상머신을 만들면 매우 느려지기 때문에 가상 시스템에서 실행되는 명령어 중 원래 시스템에서 그대로 실행해도 무방한 명령어는 땡겨와서 사용(그대로 CPU에서 실행), 그렇지 않은 명령어만 에뮬레이션함
      • 에뮬레이션 : 모든 것을 소프트웨어적으로 구현
      • 가상화 : 주요 부품의 구현에서 하드웨어적 지원을 받음
컨테이너
  • 컨테이너는 코드와 모든 관련이 있는 라이브러리의 종속성을 포함해서 만든 표준 단위
  • 프로그램을 동작할 수 있도록 만든 환경에서 빠르고 신뢰성 있게 다른 환경으로 쉽게 이식할 수 있게 만든 것
  • 호스트 OS의 커널을 공유하면서 분리된 프로레스로서 실행해 마치 가상머신이 움직이는 것처럼 보이게 하는 기술이다.
  • 호스트 OS에 컨테이너 런타임을 올리고 그 위에 프로세스로서 컨테이너를 동작시킨다.
  • 컨테이너의 실체는 단순한 프로세스이므로 가상 머신에 비해 매우 가볍고 빠르게 동작할 수 있다.
  • 가상머신 vs 컨테이너 방식 

도커
  • 개요
  • 컨테이너라는 경량 단위로 애플리케이션을 실행하는 기능을 제공하는 플랫폼
  • 컨테이너를 동작시키기 위한 엔진의 하나
  • 도커가 빠르게 확산한 이유
    • 컨테이너 기술 자체는 새로운 기술이 아니었지만 도커는 아래 이유로 단기간에 개발자들의 지지를 얻음
      1. 컨테이너 관리 방식
      • 도커에서는 Dockerfile이라는 정의 파일을 작성하여 동일한 컨테이너 이미지를 간단히 만들 수 있음
      • 이는 IaC(Infrastructure as Code)를 구현하는데 매우 적합한 소프트웨어의 형태임
      • 또한 컨테이너의 이미지에는 애플리케이션과 그 실행 환경 설정이 포함되어 있기 때문에 도커 엔진만 설치되어 있다면 언제 어디서든 그 애플리케이션의 동작이 보장되는 장점도 있음(이전까지는 환경에 영향으로 프로젝트 실행이 안되는 경우가 많이 있었음)
      1. 에코 시스템
      • 컨테이너 이미지를 저장, 공유하기 위한 에코 시스템이 초기부터 준비되어 있었음
      • 생성한 컨테이너 이미지는 각 환경에 확실히 배포할 수 있어야 의미가 있으며, 도커에서는 도커 허브(Docker Hub)라는 컨테이너 이미지를 저장, 공유할 수 있는 컨테이너 저장소(Repository)가 제공됨
      • docker push/pull 명령으로 간단히 도커 허브에 컨테이너 이미지를 전송하거나 다운로드 할 수 있음
      • 이를 통해 애플리케이션을 배포할 때 환경 설정 차이로 인해 발생하기 쉬운 문제를 해결할 수 있음
      • 즉, 개발 환경에서 스테이징 환경, 서비스 환경으로 동일한 컨테이너 이미지를 배포할 수 있으므로 테스트를 거친 컨테이너 이미지를 서비스 환경에 안정적으로 배포할 수 있음
  • 동일한 컨테이너 이미지를 배포함으로써 애플리케이션 실행이 보장됨 

 

  • 도커를 통한 조직의 문제 해결
    • 도커를 이용하여 컨테이너화를 수행하면 조직의 문제도 해결이 가능하다.
    • 큰 조직, 회사 의 경우 일반적으로 인프라팀과 애플리케이션 팀으로 구분된다.
    • 어떤 시스템을 구축할 경우
      • 인프라팀: 서버 준비, 미들웨어나 프레임워크 등의 실치 및 설정
      • 애플리케이션팀 : 인프라팀이 준비한 환경에서 개발 수행
      • 기업의 규모가 클 수록 단계별 분업을 진행 

  • 이렇게 분업을 하게 되더라도 업무에 문제가 발생할 수는 있음
    • 예시
      • 인프라 초기 구축 이후 미들웨어 설정 변경 등이 필요하면 애플리케이션 팀은 항상 인프라팀에게 작업을 의뢰해야함.
      • 인프라팀은 많은 서버를 관리하고 있으므로 애플리케이션이 요구하는 환경을 제공할 때까지의 시간(리드타임)이 길어짐
      • 이 경우 애플리케이션이 Dockerfile로 미들웨어를 포함한 설정을 관리한다면 필요에 따라 빠르게 설정을 변경할 수 있음
  • 미들웨어 관리를 애플리케이션 팀이 담당할 경우 장점 

  • 인프라팀과 애플리케이션팀이 서로의 장점만을 얻는 관계로 변화 

 

  • 도커의 구성 요소
    • 도커파일(Dockerfile)
      • 운영체제, 언어, 환경 변수, 파일 위치, 네트워크 포트, 이를 실행하는 데 필요한 여타 컴포넌트를 포함하는 도커 이미지를 구축할 수 있는 일련의 명령을 제공하는 텍스트 파일
      • 각 도커 컨테이너는 도커파일과 함께 시작함
  • 도커 이미지(Docker image, Container image)
    • VM 환경의 스냅샷과 유사하며 이식 가능하고 읽기 전용의 실행 파일
    • 컨테이너를 생성하기 위한 명령, 그리고 컨테이너가 어떤 소프트웨어 컴포넌트를 어떻게 실행할 것인가에 대한 내역이 담겨 있음
  • 도커 실행 유틸리티(Docker run utility)
    • 컨테이너를 시작하는 명령
    • 각 컨테이너는 이미지 인스턴스이고, 동일 이미지의 다수의 인스턴스가 동시에 실행될 수 있음
  • 도커 허브(Docker Hub)
    • 컨테이너 이미지가 저장되고 공유되고 관리될 수 있는 저장소(Repository)
    • 컨테이너에 특화된 깃허브 도커 버전이라고 생각할 수 있음
  • 도커 엔진(Docker Engine)
    • 도커의 핵심
    • 컨테이너를 생성하고 실행하는 클라이언트-서버 기술이다. 도커 엔진은 컨테이너를 관리하는 이른바 ‘도커 대몬(Docker daemon)’이라는 장시간 실행되는 데몬 프로세스, 도커 대몬과 프로그램 사이의 통신을 담당하는 API, 명령줄 인터페이스를 포함한다.
  • 도커 컴포즈(Docker Compose)
    • YAML 파일을 이용하는 명령줄 도구이며 멀티 컨테이너 도커 애플리케이션을 정의하고 실행함
    • 이에 의해 사용자는 사용자의 구성 환경으로부터 모든 서비스를 생성하고 시작하고 정지하고 재구축할 수 있으며, 모든 실행 서비스의 현황 및 로그 출력을 열람할 수 있음
  • 도커 데스크톱(Docker Desktop)
    • 위에서 다룬 제반 컴포넌트는 도커 데스크톱 애플리케이션으로 래핑 됨
    • 이는 컨테이너화 된 애플리케이션과 마이크로서비스를 구축하고 공유하는 사용자 친화적 방식을 제공함

  • 도커의 장점
    • 도커 컨테이너는 이전의 방법보다 더 쉽게 조립하고, 유지관리하고, 이동시킬 수 있는 애플리케이션 제작 방법을 제공
    • 소프트웨어 개발자에게 아래와 같은 혜택을 제공한다.
      • 최소의 요소로 구성되어 높은 이식성을 가짐
        • 도커는 애플리케이션과 이의 환경을 격리시킴으로써 이들을 정연하고 최소한으로 유지할 수 있게 해줌
        • 이에 의해 미시적 제어와 이식성이 높아짐
      • 컴포저블(composability) 특성 보유
        • 컨테이너는 개발자가 애플리케이션의 구성 요소를 쉽게 호환되는 부분들로 된 모듈식 유닛으로 더 쉽게 조합할 수 있게 해줌
        • 이는 개발 주기, 기능 배포, 버그 수정의 속도를 높일 수 있음
      • 오케스트레이션과 스케일링 용이
        • 컨테이너는 경량이기 때문에 개발자는 많은 수의 컨테이너를 시작해 서비스 스케일링을 향상시킬 수 있음
        • 컨테이너 클러스터는 당연히 오케스트레이션이 필요하고 여기서 쿠버네티스가 등장

  • 도커의 단점
    • 도커는 가상머신이 아니다. 일종에 프레임워크라 할 수 있음
    • 컨테이너는 수많은 문제를 해결하지만 개발자가 가진 모든 난제를 해결하지는 못함
    • 도커 컨테이너는 VM이 아니다.
      • VM과 달리 컨테이너는 호스트 운영체제 리소스의 제어된 부분을 이용함
      • 따라서 요소들이 VM 수준으로 엄격히 격리되지 않음
    • 도커 컨테이너는 베어-메탈 속도를 제공하지 않는다.(베어메탈 이란? 하드웨어 상에 어떤 소프트웨어도 설치되어 있지 않은 상태를 의미함, 베어메탈 서버는 가상화를 위한 하이퍼바이저 OS없이 물리 서버를 그대로 제공하는 것을 말하며, 따라서 하드웨어에 대한 직접 제어 및 OS설정이 가능하다.)
      • 컨테이너는 VM보다 더 경량이고 베어 메탈에 더 가까움
      • 그러나 이는 성능 오버헤드를 초래함
      • 워크로드가 베어-메탈 속도를 요구한다면 컨테이너는 이에 근접한 속도를 제공하지만 동일한 속도는 아님
    • 도커 컨테이너는 스테이트리스(stateless)이며, 불변적(immutable)이다.
      • 컨테이너는 해당 콘텐츠를 담은 이미지로부터 시작되고 실행됨
      • 이미지는 기본적으로 일단 생성되면 변경되지 않음
      • 그러나 컨테이너 인스턴스는 일시적(transient)임
      • 인스턴스가 시스템 메모리로부터 제거되면 이는 영원히 사라짐
      • VM처럼 컨테이너를 세션들에 걸쳐 지속시키려면 지속성을 위한 설계가 필요함

  • 도커의 과제와 오케스트레이션 도구의 필요성
    • 단일 컨테이너가 아닌 여러 개의 컨테이너를 실행할 때 발생하는 문제의 해결
    • 보통 시스템의 구성이 커지면 컨테이너 여러 개를 연결해 서비스를 하나 만들게 되는데, 이런 구성일 때 컨테이너 사이의 통신과 가용성 확보에 대한 문제가 있음
  • 오케스트레이션
    • 여러 개의 컴퓨터 시스템, 애플리케이션 및/또는 서비스를 조율하고 관리하는 것
    • 여러 개의 작업을 함께 연결하여 크기가 큰 워크플로나 프로세스를 실행하는 방식을 취하며 이러한 프로세스는 여러 개의 자동화된 작업으로 구성될 수 있으며 관련되는 시스템도 여러 개일 수 있음
    • 오케스트레이션의 목표
      • 빈도가 높고 반복할 수 있는 프로세스의 실행을 간소화 및 최적화하여 데이터 팀이 복잡한 작업과 워크플로를 간편하게 관리하도록 돕는 것
      • 프로세스를 반복할 수 있고 작업을 자동화할 수 있다면 오케스트레이션을 사용하여 시간을 절약하고 효율성을 증대하고 중복성을 없앨 수 있다. ( 작업 오케스트레이션을 통해 데이터 및 머신 러닝을 간소화할 수 있음 )

쿠버네티스(Kubernetes)

  • 2014년 구글에서 발표한 오케스트레이션 도구
  • 컨테이너화된 워크로드와 서비스를 관리하기 위한 이식할 수 있고, 확장 가능한 오픈소스 플랫폼 선언적 구성과 자동화를 모두 지원함
쿠버네티스의 동작
  • 데이터 플레인이라고 불리는 서버를 여러 대 실행시켜 그 위에 가상 오케스트레이션 계층을 구축하고 거기에서 컨테이너가 동작함
  • 컨테이너 이용자는 이를 통해 컨테이너 그룹을 하나의 큰 머신 리소스로 볼 수 있게 되어 인프라를 추상화할 수 있음
    • 인프라의 관리 측면에서 볼 때, 여러 대의 서버로 구성이 가능하므로 단일 장애점을 배제할 수 있는 장점을 가짐
  • 어떤 가상 머신에서 어느 정도의 컨테이너를 동작시킬지를 관리하거나 새로운 컨테이너를 배포할 때 어떤 가상 머신에 배포하면 좋을지 등을 자동으로 판단함
  • 장애가 발생한 컨테이너를 정지시키고 재시작하는 구조를 가짐
  • 이러한 기능은 컨트롤 플레인이라는 마스터 노드 그룹에서 구현됨
  • 이 외에도 수많은 기능으로 구성됨(쿠버네티스가 어려워지는 이유)
  • 쿠버네티스의 구성 

 

  • 쿠버네티스의 필요성
    • 컨테이너는 애플리케이션을 포장하고 실행하는 좋은 방법임
    • 그러나 프로덕션 환경에서는 애플리케이션을 실행하는 컨테이너를 관리하고 가동 중지 시간이 없는지 확인해야 함
      • 예: 컨테이너가 다운되면 다른 컨테이너를 다시 시작해야 함
    • 이 문제를 시스템에 의해 처리한다면 더 쉽지 않을까? → 쿠버네티스가 필요한 이유
  • 쿠버네티스가 할 수 있는 일
    • 분산 시스템을 탄력적으로 실행하기 위한 프레임 워크를 제공
    • 애플리케이션의 확장과 장애 조치를 처리하고, 배포 패턴 등을 제공
    • 서비스 디스커버리와 로드 밸런싱(컨테이너에 대한 트래픽이 많으면, 쿠버네티스는 네트워크 트래픽을 로드밸런싱하고 배포하여 배포가 안정적이게 됨)
    • 스토리지 오케스트레이션(로컬 저장소, 공용 클라우드 공급자 등과 같이 원하는 저장소 시스템을 자동으로 탑재 가능)
    • 자동화된 롤아웃과 롤백(쿠버네티스를 사용하여 배포된 컨테이너의 원하는 상태를 서술 가은)
    • 자동화된 빈 패킹(bin packing) (컨테이너화된 작업을 실행하는데 사용할 수 있는 쿠버네티스 클러스터 노드를 제공)
    • 자동화된 복구(self-healing) (실패한 컨테이너를 다시 시작하고, 컨테이너를 교체하며, '사용자 정의 상태 검사'에 응답하지 않는 컨테이너를 죽이고, 서비스 준비가 끝날 때까지 그러한 과정을 클라이언트에 보여주지 않음)
    • 시크릿과 구성 관리(암호, OAuth 토큰 및 SSH 키와 같은 중요한 정보를 저장하고 관리 가능하며, 컨테이너 이미지 재구성 없이, 스택 구성에 시크릿 노출 않고도 시크릿 및 애플리 케이션 구성을 배포 및 업데이트 할 수 있음)
  • 참고: https://kubernetes.io/ko/docs/concepts/overview/working-with-objects/
     
 

쿠버네티스 오브젝트로 작업하기

쿠버네티스 오브젝트는 쿠버네티스 시스템의 영구 엔티티이다. 쿠버네티스는 이러한 엔티티들을 사용하여 클러스터의 상태를 나타낸다. 쿠버네티스 오브젝트 모델과 쿠버네티스 오브젝트를

kubernetes.io

 

 

https://github.com/Python-Backend-Team3/Team-TIL/blob/main/9.19%20~%209.30%20%ED%9A%8C%EA%B3%A0/2024-09-27%20-%20%EC%A7%80%EC%9B%85.md

 

Team-TIL/9.19 ~ 9.30 회고/2024-09-27 - 지웅.md at main · Python-Backend-Team3/Team-TIL

Today Learned repository. Contribute to Python-Backend-Team3/Team-TIL development by creating an account on GitHub.

github.com

<오늘의 회고>

728x90