Skip to content

[DEPLOY] v0.1.0 production release#139

Merged
selnem merged 2 commits into
prodfrom
develop
Jun 18, 2026
Merged

[DEPLOY] v0.1.0 production release#139
selnem merged 2 commits into
prodfrom
develop

Conversation

@selnem

@selnem selnem commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

✨ 작업 개요

  • v0.1.0 production 배포
  • main에서 dev 검증 완료 후 prod 반영

체크리스트

  • PROD_ENV, PROD_HEALTH_URL 확인
  • prod PR 머지 후 Issueissyu Prod CI/CD green
  • prod /health 200 확인

selnem added 2 commits June 18, 2026 19:51
develop 중심 CI와 OIDC EB 배포(스모크·롤백)를 도입.
ci: BE 패턴 기반 FastAPI CI/CD 정비
@selnem selnem self-assigned this Jun 18, 2026
@selnem selnem added the 🚀 deploy 배포 label Jun 18, 2026
@selnem selnem merged commit 0974e4b into prod Jun 18, 2026
1 check passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a deployment issue template, a CI/CD OIDC setup guide, a runtime specification, and an infrastructure smoke test script for PostgreSQL, Redis, and S3. The review feedback highlights several critical issues: the specified Python 3.14 version is unsupported on AWS Elastic Beanstalk; dotenv_values does not load environment variables into os.environ, which will cause database connection failures; and requiring static AWS credentials in the smoke test script will break OIDC-based authentication. Suggestions are provided to use load_dotenv, simplify the environment variable retrieval helper, and make AWS keys optional to support OIDC.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread runtime.txt
@@ -0,0 +1 @@
python-3.14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

현재 runtime.txtpython-3.14가 명시되어 있습니다. Python 3.14는 아직 정식 출시되지 않은 버전이며, AWS Elastic Beanstalk 플랫폼에서도 지원하지 않습니다. 일반적으로 Elastic Beanstalk에서 지원하는 최신 안정 버전인 python-3.11 또는 python-3.12 등으로 수정해야 배포 실패를 방지할 수 있습니다.

python-3.11

Comment thread scripts/ci_infra_smoke.py

import asyncpg
import boto3
from dotenv import dotenv_values

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

dotenv_values.env 파일의 값을 파싱하여 딕셔너리로 반환할 뿐, os.environ에 환경 변수를 등록하지 않습니다. 이로 인해 check_postgres 등에서 os.getenv를 호출할 때 .env 파일에 정의된 환경 변수를 읽지 못하는 문제가 발생합니다. load_dotenv를 사용하여 환경 변수를 실제 프로세스 환경에 로드하도록 수정하는 것을 권장합니다.

Suggested change
from dotenv import dotenv_values
from dotenv import load_dotenv

Comment thread scripts/ci_infra_smoke.py
Comment on lines +16 to +24
def get_env_value(env: dict[str, str | None], *keys: str, required: bool = False) -> str | None:
for key in keys:
value = env.get(key) or os.getenv(key)
if value:
return value
if required:
joined_keys = ", ".join(keys)
raise RuntimeError(f"Missing required env key: {joined_keys}")
return None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

load_dotenv를 사용해 환경 변수를 프로세스에 직접 로드하면, get_env_value 함수에서 env 딕셔너리를 매개변수로 전달받을 필요 없이 os.getenv를 통해 일관되게 값을 조회할 수 있습니다. 함수 시그니처를 단순화하여 가독성을 높일 수 있습니다.

Suggested change
def get_env_value(env: dict[str, str | None], *keys: str, required: bool = False) -> str | None:
for key in keys:
value = env.get(key) or os.getenv(key)
if value:
return value
if required:
joined_keys = ", ".join(keys)
raise RuntimeError(f"Missing required env key: {joined_keys}")
return None
def get_env_value(*keys: str, required: bool = False) -> str | None:
for key in keys:
value = os.getenv(key)
if value:
return value
if required:
joined_keys = ", ".join(keys)
raise RuntimeError(f"Missing required env key: {joined_keys}")
return None

Comment thread scripts/ci_infra_smoke.py
Comment on lines +27 to +34
async def check_postgres() -> None:
conn = await asyncpg.connect(
user=os.getenv("LOCAL_DB_USER", "postgres"),
password=os.getenv("LOCAL_DB_PASSWORD", "postgres"),
database=os.getenv("LOCAL_DB_NAME", "app"),
host=os.getenv("LOCAL_DB_HOST", "127.0.0.1"),
port=int(os.getenv("LOCAL_DB_PORT", "5432")),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

check_postgres에서도 os.getenv 대신 get_env_value를 사용하도록 수정하여 일관성을 유지하고, 환경 변수가 비어 있거나 누락되었을 때의 기본값 처리를 안전하게 수행할 수 있도록 개선합니다.

Suggested change
async def check_postgres() -> None:
conn = await asyncpg.connect(
user=os.getenv("LOCAL_DB_USER", "postgres"),
password=os.getenv("LOCAL_DB_PASSWORD", "postgres"),
database=os.getenv("LOCAL_DB_NAME", "app"),
host=os.getenv("LOCAL_DB_HOST", "127.0.0.1"),
port=int(os.getenv("LOCAL_DB_PORT", "5432")),
)
async def check_postgres() -> None:
conn = await asyncpg.connect(
user=get_env_value("LOCAL_DB_USER") or "postgres",
password=get_env_value("LOCAL_DB_PASSWORD") or "postgres",
database=get_env_value("LOCAL_DB_NAME") or "app",
host=get_env_value("LOCAL_DB_HOST") or "127.0.0.1",
port=int(get_env_value("LOCAL_DB_PORT") or "5432"),
)

Comment thread scripts/ci_infra_smoke.py
Comment on lines +42 to +46
def check_redis(env: dict[str, str | None]) -> None:
redis_host = get_env_value(env, "REDIS_LOCAL_HOST", "LOCAL_REDIS_HOST") or "localhost"
redis_port = int(get_env_value(env, "REDIS_LOCAL_PORT", "LOCAL_REDIS_PORT") or "6379")
redis_client = Redis(host=redis_host, port=redis_port, db=0, decode_responses=True)
assert redis_client.ping() is True

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

check_redis 함수에서 불필요해진 env 매개변수를 제거하고, 단순화된 get_env_value를 사용하도록 수정합니다.

Suggested change
def check_redis(env: dict[str, str | None]) -> None:
redis_host = get_env_value(env, "REDIS_LOCAL_HOST", "LOCAL_REDIS_HOST") or "localhost"
redis_port = int(get_env_value(env, "REDIS_LOCAL_PORT", "LOCAL_REDIS_PORT") or "6379")
redis_client = Redis(host=redis_host, port=redis_port, db=0, decode_responses=True)
assert redis_client.ping() is True
def check_redis() -> None:
redis_host = get_env_value("REDIS_LOCAL_HOST", "LOCAL_REDIS_HOST") or "localhost"
redis_port = int(get_env_value("REDIS_LOCAL_PORT", "LOCAL_REDIS_PORT") or "6379")
redis_client = Redis(host=redis_host, port=redis_port, db=0, decode_responses=True)
assert redis_client.ping() is True

Comment thread scripts/ci_infra_smoke.py
Comment on lines +49 to +67
def check_s3(env: dict[str, str | None]) -> None:
aws_access_key = get_env_value(env, "AWS_ACCESS_KEY", required=True)
aws_secret_key = get_env_value(env, "AWS_SECRET_KEY", required=True)
aws_region = get_env_value(env, "AWS_REGION", required=True)
aws_bucket = get_env_value(env, "AWS_BUCKET", required=True)

s3 = boto3.client(
"s3",
aws_access_key_id=aws_access_key,
aws_secret_access_key=aws_secret_key,
region_name=aws_region,
)
s3.head_bucket(Bucket=aws_bucket)
key = f"ci-smoke/{uuid.uuid4().hex}.txt"
body = b"ci-smoke-test"
s3.put_object(Bucket=aws_bucket, Key=key, Body=body, ContentType="text/plain")
obj = s3.get_object(Bucket=aws_bucket, Key=key)
assert obj["Body"].read() == body
s3.delete_object(Bucket=aws_bucket, Key=key)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

OIDC 기반 인증을 도입하는 경우, GitHub Actions 환경에서는 정적 AWS_ACCESS_KEYAWS_SECRET_KEY 대신 임시 자격 증명(OIDC/IAM Role)을 사용하게 됩니다. AWS_ACCESS_KEYAWS_SECRET_KEY를 필수(required=True)로 요구하면 OIDC 환경에서 스모크 테스트가 실패하게 됩니다.

따라서 해당 키들을 선택 사항으로 변경하고, 제공되지 않았을 때는 boto3가 기본 자격 증명 체인(OIDC 환경 변수 등)을 통해 자동으로 인증하도록 수정해야 합니다.

Suggested change
def check_s3(env: dict[str, str | None]) -> None:
aws_access_key = get_env_value(env, "AWS_ACCESS_KEY", required=True)
aws_secret_key = get_env_value(env, "AWS_SECRET_KEY", required=True)
aws_region = get_env_value(env, "AWS_REGION", required=True)
aws_bucket = get_env_value(env, "AWS_BUCKET", required=True)
s3 = boto3.client(
"s3",
aws_access_key_id=aws_access_key,
aws_secret_access_key=aws_secret_key,
region_name=aws_region,
)
s3.head_bucket(Bucket=aws_bucket)
key = f"ci-smoke/{uuid.uuid4().hex}.txt"
body = b"ci-smoke-test"
s3.put_object(Bucket=aws_bucket, Key=key, Body=body, ContentType="text/plain")
obj = s3.get_object(Bucket=aws_bucket, Key=key)
assert obj["Body"].read() == body
s3.delete_object(Bucket=aws_bucket, Key=key)
def check_s3() -> None:
aws_access_key = get_env_value("AWS_ACCESS_KEY")
aws_secret_key = get_env_value("AWS_SECRET_KEY")
aws_region = get_env_value("AWS_REGION", required=True)
aws_bucket = get_env_value("AWS_BUCKET", required=True)
client_kwargs = {"region_name": aws_region}
if aws_access_key and aws_secret_key:
client_kwargs["aws_access_key_id"] = aws_access_key
client_kwargs["aws_secret_access_key"] = aws_secret_key
s3 = boto3.client("s3", **client_kwargs)
s3.head_bucket(Bucket=aws_bucket)
key = f"ci-smoke/{uuid.uuid4().hex}.txt"
body = b"ci-smoke-test"
s3.put_object(Bucket=aws_bucket, Key=key, Body=body, ContentType="text/plain")
obj = s3.get_object(Bucket=aws_bucket, Key=key)
assert obj["Body"].read() == body
s3.delete_object(Bucket=aws_bucket, Key=key)

Comment thread scripts/ci_infra_smoke.py
Comment on lines +70 to +76
def main() -> int:
env = dotenv_values(".env")
asyncio.run(check_postgres())
check_redis(env)
check_s3(env)
print("infra smoke OK")
return 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

main 함수에서 dotenv_values 대신 load_dotenv를 호출하고, env 딕셔너리를 전달하지 않도록 단순화된 함수들을 호출하도록 수정합니다.

Suggested change
def main() -> int:
env = dotenv_values(".env")
asyncio.run(check_postgres())
check_redis(env)
check_s3(env)
print("infra smoke OK")
return 0
def main() -> int:
load_dotenv()
asyncio.run(check_postgres())
check_redis()
check_s3()
print("infra smoke OK")
return 0

Comment thread docs/cicd-oidc-setup.md

## EB Python 플랫폼

`runtime.txt`에 `python-3.14`를 명시했습니다. dev/prod EB 환경이 Python 3.14 플랫폼을 지원하는지 확인하고, 미지원 시 플랫폼 업그레이드를 선행하세요.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

가이드 문서에 언급된 Python 버전도 python-3.14 대신 실제 사용 중인 Python 버전(예: python-3.11 또는 python-3.12)으로 수정하여 혼선을 방지해 주세요.

Suggested change
`runtime.txt``python-3.14` 명시했습니다. dev/prod EB 환경이 Python 3.14 플랫폼을 지원하는지 확인하고, 미지원 시 플랫폼 업그레이드를 선행하세요.
runtime.txt에 python-3.11을 명시했습니다. dev/prod EB 환경이 Python 3.11 플랫폼을 지원하는지 확인하고, 미지원 시 플랫폼 업그레이드를 선행하세요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant