결론부터 알고 싶으신 분들은 'AWS Lambda 환경 변수 기능 활용하기'으로 바로 넘어가시면 됩니다.
프로젝트를 진행하다 보면 api key 값이라던가... 아이디 패스워드 값이라던가.. 중요한 정보를 관리해야할 필요가 있다. 이전 프로젝트에서는 그런 값들이 필요가 없어서 그냥 이미지화하고 ecr에 업로드해서 lambda함수를 생성했었는데 이번에는 elastic search의 클라우드 id나 인덱스 명, api key값 등 중요한 정보를 숨겨야 했다. 그렇다면 이 값들을 어떻게 관리할 수 있을까? 총 두가지 방법으로 나눌 수 있다.
Docker 환경에서는 위 파일을 통해 여러 컨테이너의 설정을 정의하고 각 컨테이너에 필요한 환경변수를 설정할 수 있다. 이 방법은 로컬 개발환경이나 Docker를 사용하는 다른 환경에서 특히 유형하다.
version: '3'
services:
myservice:
image: myimage
environment:
ELASTIC_CLOUD_ID: "my_cloud_id"
ELASTIC_API_KEY: "my_api_key"
env_file:
- .env
위 코드처럼 yml 파일을 작성할 수 있는데 여기서 environment
는 직접 환경 변수를 명시적으로 설정할 수 있게하고 env_file
섹션은 .env
파일로부터 환경변수를 로드한다.
AWS Lambda에서는 AWS CLI를 사용해 함수의 환경 변수를 설정하거나 업데이트를 할 수 있다. 이 방법은 AWS 환경에서 Lambda함수를 배포하고 관리할 대 사용된다.
aws lambda update-function-configuration --function-name my-function \
--environment "Variables={ELASTIC_CLOUD_ID=my_cloud_id,ELASTIC_API_KEY=my_api_key}"
이 명령은 my-function
이라는 이름의 Lambda 함수에 ELASTIC_CLOUD_ID와 ELASTIC_API_KEY라는 환경 변수를 설정한다.
docker-compose.yml
이나 Dockerfile의 ENV
지시어를 사용하여 환경 변수를 설정한다. 이는 개발, 테스트 등 Docker를 사용하는 환경에 적합하다.docker-compose.yml
파일이나 Dockerfile에 직접 민감한 정보를 포함시키지 않는 것이 중요하다. 이런 파일들이 Git 같은 버전 관리 시스템에 포함될 경우, 민감한 정보가 노출될 위험이 있기 때문..env
)을 사용할 경우: Docker Compose를 사용하고 .env
파일에서 환경 변수를 로드하는 경우, 이 파일을 이미지에 포함시키지 않도록 주의해야 한다. 또한, .env
파일을 Git이나 다른 버전 관리 시스템에서 제외시켜야 한다(.gitignore
에 추가).결론 : 이미지화할 때는 yml 파일이던 .env 파일이던 노출될 가능성이 존재하니 다른 방법을 고려해라.
Docker 이미지에 환경 변수를 포함하려 할 때, docker-compose.yml
파일에 환경 변수를 직접 작성하는 것이 보안적으로 우려될 수 있다. 특히, 민감한 정보를 다루는 경우 더욱 그렇다고 한다. (아직 실무를 접하지 않아서 모르지만...) 하지만 Docker 이미지 빌드 과정에서 환경 변수를 안전하게 포함하는 방법은 여러 가지가 존재한다고 한다. 그 방법은 아래와 같다.
Dockerfile에서 ARG
지시어를 사용하여 빌드 시간 변수를 정의할 수 있습니다. 이 방법은 이미지를 빌드할 때만 변수를 사용할 수 있으며, 빌드가 완료된 후 이미지에 변수를 남기지 않습니다. 민감한 정보를 빌드 과정에서만 사용해야 할 때 유용하다.
# Dockerfile
ARG ELASTIC_CLOUD_ID
ARG ELASTIC_API_KEY
# ARG로 받은 값을 환경 변수로 설정
ENV ELASTIC_CLOUD_ID=${ELASTIC_CLOUD_ID}
ENV ELASTIC_API_KEY=${ELASTIC_API_KEY}
Docker 이미지를 빌드할 때는 --build-arg
옵션을 사용하여 값을 전달한다:
docker build --build-arg ELASTIC_CLOUD_ID=your_cloud_id --build-arg ELASTIC_API_KEY=your_api_key -t your_image_name .
하지만 이 방법은 환경변수가 많을 수록 cli 코드 관리가 힘들다는 단점이 있는 것 같다.
Docker 이미지를 실행할 때 docker run
명령어의 -e
또는 --env
옵션을 사용하여 환경 변수를 컨테이너에 전달할 수 있다. 이 방법은 이미지에 민감한 정보를 포함시키지 않고, 컨테이너 실행 시 필요한 환경 변수를 제공할 수 있다.
docker run -e ELASTIC_CLOUD_ID=your_cloud_id -e ELASTIC_API_KEY=your_api_key your_image_name
환경 변수를 포함한 파일을 작성하고, 이 파일을 docker run
명령어의 --env-file
옵션을 통해 컨테이너에 전달할 수 있다. 이 파일은 런타임에만 사용되며, 이미지에는 포함되지 않는다.
# .env 파일
ELASTIC_CLOUD_ID=your_cloud_id
ELASTIC_API_KEY=your_api_key
docker run --env-file .env your_image_name
2번과 3번 방법은 Docker 이미지를 실행할 때 환경변수를 전달하는 방법이라 이미지를 빌드할 때는 사용할 수 없고 런타임에 컨테이너 환경에 환경 변수를 주입하는 데 사용되어 말그대로 테스트 용도이다.
위에 내용에서 알 수 있듯이 도커 이미지 빌드에서 환경변수를 설정하는 것은 말그대로 !!테스트!! 즉 로컬에서 돌려볼 때 적합한 작업인 것 같고 결국 배포할 때 환경변수를 관리하기 위해서는 AWS 라는 기업의 서비스를 이용하는 것이 좋다.
이것외에도 멀티-스테이지 빌드를 사용할 수 있다고 하는데 나중에 알아보자.
AWS Lambda에서 Docker 컨테이너 이미지를 사용할 때, 민감한 정보를 포함하지 않고 환경 변수를 안전하게 관리하려면, AWS Lambda의 환경 변수 기능을 활용해야 한다. 이 방법을 사용하면 Docker 이미지에 민감한 정보를 포함시킬 필요 없이, Lambda 함수 실행 시 필요한 환경 변수를 제공할 수 있다.
람다 함수 내부에서는 아래와 같은 방식으로 접근할 수 있다.
import os
ELASTIC_CLOUD_ID = os.getenv('ELASTIC_CLOUD_ID')
ELASTIC_API_KEY = os.getenv('ELASTIC_API_KEY')
# 환경 변수 사용...
Lambda 함수가 실행될 때 AWS는 설정된 환경 변수를 Lambda 실행 환경에 주입하므로, 애플리케이션 코드에서 필요한 구성 정보를 안전하게 사용할 수 있다.
람다 함수 코드, 관련된 함수 코드 파일, 도커파일 등등 필요한 것들을 이미지로 말기위한 준비를 해야된다. 뭐 이것은 검색하면 다 나오기 때문에 생략한다. 그치만 나의 탐구욕은 멈출 수 없다. 모든 것은 이해했으나 왜 작업 디렉토리가 WORKDIR /var/task
여기일까?
AWS Lambda에서 Docker 컨테이너 이미지를 사용할 때, /var/task
디렉토리는 Lambda 실행 환경에서 코드와 라이브러리 파일들을 찾는 기본 위치이다.
AWS Lambda의 컨테이너 이미지 지원은 이 위치에서 함수 코드를 실행하기를 예상하고 있고 WORKDIR
을 /var/task
로 설정하는 것은 Lambda 함수가 올바르게 실행되도록 하는 데 중요하다고 한다.
Lambda 실행 환경은 /var/task
디렉토리를 함수 코드와 그 의존성이 있는 '작업 디렉토리'로 사용한다. 이 경로를 기준으로 Python 모듈을 찾고, 핸들러 함수를 지정할 때의 참조 경로 역시 이 디렉토리를 기반으로 한다.
예를 들어,
CMD ["query.lambda_handler"]
에서query
는/var/task
디렉토리 내의query.py
파일을 가리킨다.
WORKDIR
을 다른 위치로 설정하게 되면 Lambda 함수가 정상적으로 실행되지 않거나, 코드나 라이브러리를 찾지 못하는 문제가 발생할 수 있다. 따라서, AWS Lambda에서 Docker 컨테이너를 사용할 때는 WORKDIR
을 /var/task
로 설정하는 것이 권장되며, 이는 Lambda의 기본 실행 환경과 일치하도록 설정된 것이다.
WORKDIR의 설정은 사용하는 프로그래밍 언어에 직접적으로 의존적이지 않다. 대신, 애플리케이션의 구조, 사용하는 베이스 이미지의 관례, 그리고 특정 실행 환경(AWS Lambda와 같은)의 요구사항에 따라 결정된다.
자세한 건 역시 공식문서 가 최고지요?!
이미지 빌드:
docker build -t lambda-function-image .
Amazon ECR 리포지토리 생성(미리 생성하지 않았다면):
aws ecr create-repository --repository-name lambda-function-repo
이건 gui 상에서도 가능하다! 굳이 cli 사용하지 않아도 됨.
근데 cli 상에서 aws 명령어를 사용하려면 aws configure 설정 해야된다.
📍 configure 설정 시 등록하는 id와 key 값은 aws id, passwd가 아니다. aws iam -> 사용자 -> 보안 자격증명 -> 액세스 키로 발급해야 한다. (사실 내가 했던 실수지롱)
📍 ECR 레포 생성시 프라이빗으로 설정해야지 lambda와 연결 가능하다.
Docker 로그인:
aws ecr get-login-password --region your-region | docker login --username AWS --password-stdin your-account-id.dkr.ecr.your-region.amazonaws.com
이미지 태그 지정:
docker tag <source_image>:<tag> <repository_url>:<tag>
<source_image>:<tag>
는 로컬에서 사용하고 있는 이미지의 이름과 태그이다. 예를 들어, lambda-function-image:latest
에서 lambda-function-image
는 이미지 이름이고, latest
는 이미지의 태그이다.<repository_url>
는 이미지가 저장될 ECR 리포지토리의 URL이다. 여기에는 AWS 계정 ID, ECR 서비스의 도메인, 리전, 그리고 리포지토리 이름이 포함된다.your-account-id.dkr.ecr.your-region.amazonaws.com/lambda-function-repo
.<tag>
는 리포지토리에 푸시될 때 사용될 이미지의 태그이다. 이 태그를 통해 동일한 이미지의 다양한 버전을 구분할 수 있다. 예를 들어, latest
, v1
, v2
등과 같이 사용될 수 있다.ECR에 이미지 푸시:
docker push your-account-id.dkr.ecr.your-region.amazonaws.com/lambda-function-repo:latest
📌 주의! 레포이름과 url 주소 잘 봐라... 안그러면 EOF 에러를 만나게 될 수도...
(는 내얘기)
위 과정을 통해 완료해보자!
람다 함수를 만들 때 만든 ecr 레포를 참고해서 생성한다.
함수 대시보드에서 "구성" 탭을 선택한다.
좌측 사이드바에서 "환경 변수"를 선택한다.
그다음 편집~~
여기서 키(key)와 값(value)을 입력하면 된다.
콘솔에서 말고 cli를 사용해 설정하는 방법도 있다.
aws lambda update-function-configuration --function-name my-function \
--environment "Variables={ELASTIC_CLOUD_ID=my_cloud_id,ELASTIC_API_KEY=my_api_key,ELASTIC_INDEX=my_index,ELASTIC_MODEL=my_model}"
여기서 my-function은 Lambda 함수의 이름이며, --environment 옵션 뒤에는 환경 변수들의 키-값 쌍을 JSON 형식으로 제공한다.
포스트맨으로 확인했을 때 결과값 잘 나오는 것을 확인할 수 있었다!
사실 여기서 무슨
Error: fork/exec /lambda-entrypoint.sh: exec format error Runtime.InvalidEntrypoint
에러가 났었는데 동네방네 팔짝뛰며 찾아본 결과 도커파일에서 FROM 즉 베이스 이미지를 지정하는 지시어의 코드가 어긋나있었다.
장장 5시간을 공들이며 작성한... 블로그글...
개발만 했을 때는 몰랐지만 남들이 보기 쉽게끔 정제하며 작성하는 게 은근 많이 어렵고 시간이 많이 드는 구나... 를 체감했다. 그러나 작성하면서 나도 개념 정리 + 회고를 진행할 수 있어서 좋다!
사실 이게 apigateway를 사용해야 되는데 일단 테스트 코드가 잘 되는지 확인하기 위해 퍼블릭 url로 통신했다. 그래서 다음 주제는... lambda와 api gateway를 연결하는 것에 대해 다루겠다.
안뇽~~~ 👋👋👋