요약
Docker 초보 가이드 2026: 개발 환경부터 배포까지 컨테이너 마스터하기
2026년, 현대 개발의 필수 도구인 Docker의 기본 개념부터 실제 활용까지, 초보자도 쉽게 따라 할 수 있도록 상세히 설명합니다.
핵심 키워드: 컨테이너, 개발 환경 효율화, 애플리케이션 배포
이 글의 순서
1. 배경/도입: 왜 Docker를 사용해야 할까요?
2. 핵심 내용: Docker 기본 개념 파헤치기
3. 핵심 내용: 개발 환경 컨테이너화
4. 핵심 내용: 애플리케이션 컨테이너화 및 이미지 빌드
5. 문제 해결: 일반적인 Docker 문제와 해결책
6. 실전 적용: Docker를 이용한 애플리케이션 배포
7. 자주 묻는 질문 (FAQ)
8. 마무리: Docker, 2026년에도 여전히 강력한 이유
배경/도입
왜 Docker를 사용해야 할까요?
안녕하세요, 권퓨터입니다! 2026년 현재, 소프트웨어 개발 환경은 점점 더 복잡해지고 있습니다. 다양한 프로그래밍 언어, 프레임워크, 데이터베이스, 그리고 운영체제까지, 개발자가 신경 써야 할 요소들이 한두 가지가 아니죠. 이러한 환경 속에서 “제 컴퓨터에서는 잘 되는데, 다른 환경에서는 안 돼요!” 같은 고질적인 문제는 여전히 개발자들의 골치를 썩이고 있습니다. 바로 이 문제를 해결하기 위해 등장한 혁신적인 기술이 바로 Docker(도커)입니다.
과거에는 개발 환경을 맞추기 위해 가상 머신(VM)을 많이 사용했습니다. VM은 하나의 물리 서버 위에 여러 개의 독립적인 운영체제를 설치하여 사용하는 방식이었죠. 하지만 VM은 각 운영체제마다 커널을 포함하기 때문에 용량이 크고, 시작하는 데 시간도 오래 걸리며, 자원 소모도 많다는 단점이 있었습니다. 마치 하나의 아파트에 여러 채의 단독주택을 짓는 것과 같았죠.
2013년에 처음 등장한 Docker는 이러한 VM의 한계를 극복하며 컨테이너(Container)라는 새로운 개념을 제시했습니다. 컨테이너는 애플리케이션과 그 실행에 필요한 모든 파일(라이브러리, 설정 파일, 종속성 등)을 하나의 경량화된 패키지로 묶어주는 기술입니다. VM처럼 전체 운영체제를 가상화하는 것이 아니라, 호스트 운영체제의 커널을 공유하면서 애플리케이션 실행 환경만 격리하는 방식이죠. 마치 아파트의 각 층에 표준화된 규격의 ‘방’을 만들고, 그 방 안에 필요한 가구(애플리케이션)를 가져다 놓는 것과 비슷하다고 할 수 있습니다.
2026년 기준으로, Docker는 전 세계 개발자 및 기업에서 가장 널리 사용되는 컨테이너화 도구 중 하나로 자리매김했습니다. 특히 클라우드 환경에서의 애플리케이션 배포 및 마이크로서비스 아키텍처 구축에 필수적인 기술로 인식되고 있습니다. 시장 조사 기관에 따르면, 2025년까지 컨테이너 기술을 도입한 기업의 비율은 80%를 넘어설 것으로 예상되며, 그 중심에는 Docker가 있습니다. 이 글에서는 Docker의 기본 개념부터 실제 개발 환경 설정, 애플리케이션 컨테이너화, 그리고 배포에 이르는 전 과정을 초보자의 눈높이에 맞춰 쉽고 명확하게 설명해 드리겠습니다. 지금부터 권퓨터와 함께 Docker의 세계로 떠나볼까요?
핵심 포인트
Docker는 개발 환경의 불일치 문제를 해결하고, 애플리케이션을 가볍고 일관된 컨테이너 형태로 패키징하여 개발 및 배포 효율성을 극대화하는 핵심 기술입니다.
핵심 내용
Docker 기본 개념 파헤치기
Docker의 3요소: 컨테이너, 이미지, 도커 엔진
Docker를 이해하려면 다음 세 가지 핵심 요소를 알아야 합니다. 이들은 마치 레고 블록처럼 서로 유기적으로 연결되어 Docker 생태계를 구성합니다.
1. 컨테이너 (Container):
컨테이너는 애플리케이션이 실행되는 격리된 공간입니다. 여러분이 만든 프로그램과 그 프로그램이 실행되는 데 필요한 모든 것(코드, 런타임, 시스템 도구, 라이브러리 등)이 컨테이너 안에 패키징되어 있습니다. 컨테이너는 호스트 운영체제의 커널을 공유하기 때문에 가상 머신(VM)보다 훨씬 가볍고 빠르게 시작할 수 있습니다. 예를 들어, 웹 서버, 데이터베이스, 백엔드 API 서버 등을 각각의 컨테이너로 만들어 독립적으로 실행할 수 있습니다.
2. 이미지 (Image):
이미지는 컨테이너를 만들기 위한 ‘설계도’ 또는 ‘템플릿’입니다. 애플리케이션을 실행하는 데 필요한 모든 파일과 설정이 읽기 전용으로 저장되어 있습니다. 이미지는 여러 계층(Layer)으로 구성되어 있어 효율적으로 저장되고 재사용됩니다. 예를 들어, Node.js 애플리케이션을 위한 이미지는 Node.js 런타임, 필요한 라이브러리, 그리고 여러분의 애플리케이션 코드를 포함할 수 있습니다. 이미지는 Docker Hub와 같은 레지스트리에 저장되어 공유될 수 있습니다.
3. 도커 엔진 (Docker Engine):
도커 엔진은 Docker의 핵심 구성 요소로, 클라이언트-서버 구조를 가집니다. 사용자가 docker 명령어를 통해 클라이언트(CLI)에서 명령을 내리면, 데몬(daemon)이라고 불리는 서버 프로세스가 해당 명령을 받아 이미지를 빌드하고 컨테이너를 실행하거나 관리하는 모든 작업을 수행합니다. 도커 엔진 덕분에 개발자는 복잡한 컨테이너 관리 작업을 간편하게 처리할 수 있습니다.
Docker 컨테이너 vs. 가상 머신 (VM)
Docker 컨테이너와 가상 머신(VM)은 모두 격리된 환경을 제공하지만, 작동 방식과 효율성에서 큰 차이를 보입니다. 아래 표를 통해 비교해 보세요.
| 구분 | Docker 컨테이너 | 가상 머신 (VM) |
|---|---|---|
| 가상화 방식 | 운영체제 수준 가상화 (커널 공유) | 하드웨어 수준 가상화 (하이퍼바이저) |
| 운영체제 | 호스트 OS 커널 공유 | 각 VM마다 독립적인 게스트 OS 포함 |
| 자원 효율성 | 매우 높음 (경량, 적은 자원 소모) | 낮음 (무겁고 많은 자원 소모) |
| 시작 속도 | 초 단위 (빠름) | 분 단위 (느림) |
| 용량 | MB 단위 (작음) | GB 단위 (큼) |
| 주요 용도 | 애플리케이션 배포, 마이크로서비스 | 운영체제 격리, 다양한 OS 환경 |
보시는 것처럼 컨테이너는 VM에 비해 훨씬 가볍고 효율적입니다. 이러한 특징 덕분에 Docker는 현대 애플리케이션 개발 및 배포의 표준 기술로 빠르게 자리 잡을 수 있었습니다.


Docker Compose: 여러 컨테이너를 한 번에 관리하기
실제 애플리케이션은 보통 웹 서버, 데이터베이스, 캐시 서버 등 여러 개의 독립적인 서비스로 구성됩니다. 이들을 각각 개별 컨테이너로 실행하고 관리하는 것은 번거로운 일인데요. 이때 Docker Compose가 빛을 발합니다. Docker Compose는 여러 개의 컨테이너를 하나의 애플리케이션으로 묶어 YAML 파일(docker-compose.yml)에 정의하고, 한 번의 명령으로 이 모든 컨테이너를 함께 실행, 중지, 빌드할 수 있게 해줍니다.
예를 들어, 웹 애플리케이션(Node.js), 데이터베이스(MongoDB), 그리고 캐시(Redis)를 사용하는 프로젝트라면, 이 세 가지 서비스를 docker-compose.yml 파일 하나로 정의하고 docker compose up 명령만으로 전체 개발 환경을 쉽게 구축할 수 있습니다. 이는 개발 환경 설정 시간을 획기적으로 단축시켜 줍니다.
핵심 포인트
Docker는 이미지(설계도)를 기반으로 컨테이너(실행 환경)를 생성하며, 도커 엔진이 이 모든 과정을 관리합니다. 특히 Docker Compose는 복잡한 다중 컨테이너 애플리케이션을 효율적으로 관리할 수 있게 돕습니다.
핵심 내용
개발 환경 컨테이너화
Docker의 가장 강력한 장점 중 하나는 개발 환경을 표준화하고 효율적으로 관리할 수 있다는 것입니다. 팀원마다 다른 운영체제나 라이브러리 버전을 사용해도 Docker 컨테이너를 이용하면 모두 동일한 환경에서 개발할 수 있습니다. 이는 “내 컴퓨터에서는 되는데 네 컴퓨터에서는 안 돼”라는 불필요한 논쟁을 없애주고, 새로운 개발자가 프로젝트에 합류했을 때 온보딩(On-boarding) 시간을 획기적으로 단축시켜 줍니다.
Node.js & MongoDB 개발 환경 구축 예시
간단한 Node.js 웹 애플리케이션과 MongoDB 데이터베이스를 Docker Compose로 함께 실행하는 예시를 보여드리겠습니다. 이 예시를 통해 여러분은 단 몇 줄의 설정만으로 완벽한 개발 환경을 갖출 수 있습니다.
코드 설명
아래 docker-compose.yml 파일은 Node.js 애플리케이션과 MongoDB 데이터베이스 두 개의 서비스를 정의합니다. Node.js 서비스는 현재 디렉토리의 Dockerfile을 사용하여 빌드되고, 호스트의 3000번 포트와 연결됩니다. MongoDB 서비스는 공식 이미지를 사용하고, 데이터 영속성을 위해 볼륨을 설정합니다.
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
depends_on:
- db
environment:
NODE_ENV: development
MONGO_URI: mongodb://db:27017/myapp_dev
db:
image: mongo:4.4
volumes:
- mongo_data:/data/db
volumes:
mongo_data:
위 docker-compose.yml 파일과 함께, Node.js 애플리케이션을 위한 Dockerfile이 필요합니다. 예를 들어 다음과 같이 구성할 수 있습니다.
코드 설명
이 Dockerfile은 Node.js 16 버전 이미지를 기반으로 애플리케이션을 빌드합니다. 작업 디렉토리를 설정하고, 의존성을 설치한 후, 애플리케이션 코드를 복사하여 실행합니다.
# Dockerfile (Node.js 서비스용)
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
이제 프로젝트 루트 디렉토리에서 다음 명령어를 실행하면, Node.js 웹 서버와 MongoDB 데이터베이스가 동시에 실행됩니다.
코드 설명
이 명령어는 docker-compose.yml 파일에 정의된 모든 서비스를 백그라운드(-d)에서 빌드하고 실행합니다. 컨테이너들이 모두 정상적으로 실행되면, 웹 브라우저에서 http://localhost:3000으로 접속하여 Node.js 애플리케이션을 확인할 수 있습니다.
docker compose up -d

이렇게 Docker Compose를 활용하면 복잡한 개발 환경 설정에 드는 시간을 크게 줄이고, 팀 전체의 생산성을 향상시킬 수 있습니다. 특히 2026년에는 AI 개발 환경에서도 Docker를 활용하여 GPU 드라이버 및 딥러닝 프레임워크 버전을 통일하는 데 적극적으로 사용되고 있습니다.
핵심 포인트
Docker Compose는 여러 컨테이너로 구성된 개발 환경을 docker-compose.yml 파일 하나로 정의하여, 개발자 온보딩 시간을 단축하고 환경 불일치 문제를 해소하는 데 결정적인 역할을 합니다.
핵심 내용
애플리케이션 컨테이너화 및 이미지 빌드
애플리케이션을 Docker 컨테이너로 만들기 위해서는 먼저 Dockerfile을 작성해야 합니다. Dockerfile은 Docker 이미지를 빌드하기 위한 명령어들을 순서대로 나열해 놓은 텍스트 파일입니다. 이 파일을 통해 어떤 기본 이미지를 사용할지, 어떤 파일을 복사할지, 어떤 의존성을 설치할지 등을 정의할 수 있습니다. 잘 작성된 Dockerfile은 작고 효율적인 이미지를 만들어 배포 시간을 단축시키고 자원 효율성을 높입니다.
Dockerfile 작성 가이드
Dockerfile의 주요 명령어들을 알아보고, 간단한 Python Flask 애플리케이션을 컨테이너화하는 예시를 살펴보겠습니다.
Dockerfile 핵심 명령어
FROM — 베이스 이미지 지정 (예: python:3.9-slim)
WORKDIR — 컨테이너 내부 작업 디렉토리 설정
COPY — 호스트의 파일/디렉토리를 컨테이너로 복사
RUN — 이미지 빌드 시 실행될 명령어 (예: 패키지 설치)
EXPOSE — 컨테이너가 리스닝하는 포트 지정 (문서화 목적)
CMD — 컨테이너 시작 시 실행될 기본 명령어
ENTRYPOINT — 컨테이너 시작 시 항상 실행될 명령어 (CMD와 함께 사용)
Python Flask 애플리케이션 Dockerfile 예시
다음은 간단한 Flask 웹 애플리케이션을 위한 Dockerfile입니다. 프로젝트 구조는 다음과 같다고 가정합니다:
my-flask-app/
├── Dockerfile
├── app.py
└── requirements.txt
코드 설명
이 Dockerfile은 Python 3.9 버전을 기반으로 Flask 애플리케이션을 컨테이너화합니다. requirements.txt에 명시된 의존성을 설치한 후, app.py를 복사하여 5000번 포트로 실행합니다.
# Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
그리고 app.py와 requirements.txt는 다음과 같습니다.
코드 설명
간단한 Flask 애플리케이션 코드로, “Hello, Docker 2026!” 메시지를 반환합니다.
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello, Docker 2026!"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
코드 설명
Flask 애플리케이션의 유일한 의존성인 Flask를 명시합니다.
# requirements.txt
Flask==2.3.3
이제 Docker 이미지를 빌드하고 컨테이너를 실행해볼까요?
코드 설명
프로젝트 루트 디렉토리에서 이 명령어를 실행하면, 현재 디렉토리의 Dockerfile을 사용하여 my-flask-app:1.0이라는 이름의 이미지를 빌드합니다. 점(.)은 Dockerfile의 위치를 현재 디렉토리로 지정합니다.
docker build -t my-flask-app:1.0 .코드 설명
빌드된 이미지를 사용하여 컨테이너를 실행합니다. -p 80:5000은 호스트의 80번 포트를 컨테이너의 5000번 포트와 연결하고, -d는 백그라운드에서 실행하도록 합니다. 이제 웹 브라우저에서 http://localhost로 접속하면 Flask 애플리케이션을 확인할 수 있습니다.
docker run -p 80:5000 -d my-flask-app:1.0
이미지 최적화 팁: 멀티스테이지 빌드 & .dockerignore
작고 효율적인 이미지를 만드는 것은 매우 중요합니다. 이미지 크기가 작을수록 빌드 및 배포 시간이 단축되고, 스토리지 비용도 절감되기 때문입니다. 다음 두 가지 기법을 활용하여 이미지를 최적화할 수 있습니다.
1. 멀티스테이지 빌드 (Multi-stage Builds):
애플리케이션을 빌드하는 과정에서 필요한 도구(컴파일러, 테스트 프레임워크 등)는 최종 실행 이미지에는 필요 없는 경우가 많습니다. 멀티스테이지 빌드는 여러 FROM 명령을 사용하여 빌드 단계를 분리하고, 최종적으로 필요한 결과물만 다음 단계로 복사하여 최종 이미지 크기를 극적으로 줄이는 기법입니다. 예를 들어, 자바 애플리케이션의 경우 빌드 단계에서 JDK를 사용하고, 최종 실행 단계에서는 JRE만 포함된 이미지를 사용할 수 있습니다.
2. .dockerignore 파일 활용:
.dockerignore 파일은 .gitignore와 유사하게, Docker 이미지 빌드 시 컨텍스트(Context)에 포함시키지 않을 파일이나 디렉토리를 지정하는 데 사용됩니다. 예를 들어, node_modules, .git, .env 등은 이미지에 포함될 필요가 없으므로 .dockerignore에 추가하여 빌드 속도를 높이고 이미지 크기를 줄일 수 있습니다.
핵심 포인트
Dockerfile은 애플리케이션을 컨테이너 이미지로 만드는 ‘설계도’이며, FROM, RUN, CMD 등의 명령어로 구성됩니다. 멀티스테이지 빌드와 .dockerignore를 통해 작고 효율적인 이미지를 생성하는 것이 중요합니다.
문제 해결
일반적인 Docker 문제와 해결책
Docker는 개발 워크플로우를 혁신적으로 개선하지만, 초보자에게는 몇 가지 일반적인 문제들이 발생할 수 있습니다. 당황하지 마세요! 권퓨터가 자주 발생하는 문제들과 그 해결책을 알려드리겠습니다.
컨테이너 포트 충돌
Docker 컨테이너를 실행하려고 할 때 “port is already allocated” 또는 “address already in use”와 같은 오류 메시지가 나타나는 경우입니다. 이는 호스트 머신의 특정 포트가 이미 다른 프로세스에 의해 사용되고 있어 Docker가 해당 포트를 사용할 수 없을 때 발생합니다.
해결 — 사용 중인 포트 확인 및 변경
1. 사용 중인 포트 확인:
Windows에서는 netstat -ano | findstr :[포트번호], Linux/macOS에서는 sudo lsof -i :[포트번호] 명령어를 사용하여 어떤 프로세스가 해당 포트를 사용 중인지 확인할 수 있습니다.
2. Docker 포트 매핑 변경:
컨테이너를 실행할 때 호스트 포트를 다른 비어있는 포트로 변경하여 매핑합니다. 예를 들어, 호스트의 80번 포트 대신 8080번 포트를 사용하려면 다음과 같이 변경합니다.
docker run -p 8080:80 -d my-web-appDocker Compose를 사용한다면 docker-compose.yml 파일의 ports 섹션을 수정합니다.
services:
web:
ports:
- "8080:80" # 호스트 포트:컨테이너 포트
볼륨 마운트 권한 문제
컨테이너 내에서 호스트의 볼륨을 마운트하여 사용하려고 할 때 “Permission denied” 오류가 발생하는 경우입니다. 이는 컨테이너 내부의 프로세스가 볼륨에 접근할 권한이 없어서 발생합니다. 특히 Linux 환경에서 흔히 볼 수 있습니다.
해결 — 사용자 권한 조정 또는 user 지시어 사용
1. 호스트 디렉토리 권한 변경 (임시 방편):
가장 간단한 방법은 호스트의 해당 디렉토리 권한을 컨테이너가 접근할 수 있도록 변경하는 것입니다. 예를 들어, chmod -R 777 [디렉토리 경로] 명령을 사용할 수 있지만, 이는 보안상 좋지 않으므로 개발 환경에서만 주의해서 사용해야 합니다.
2. Dockerfile에 USER 지시어 사용:
컨테이너 내부에서 특정 사용자(예: node 또는 www-data)로 실행하도록 Dockerfile에 USER 명령을 추가합니다. 이렇게 하면 컨테이너 내부의 프로세스가 호스트 볼륨에 접근할 때 해당 사용자 권한으로 접근하게 됩니다.
FROM node:16-alpine
WORKDIR /app
# ...
RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -D appuser
USER appuser # appuser로 컨테이너 실행
3. Docker Compose에서 user 옵션 사용:
docker-compose.yml 파일에서 user 옵션을 사용하여 컨테이너를 실행할 사용자 ID를 지정할 수 있습니다. 예를 들어, 현재 호스트 사용자의 UID/GID를 컨테이너에 전달하여 권한 문제를 해결할 수 있습니다.
services:
web:
user: "${UID}:${GID}" # 현재 호스트 사용자의 UID/GID 사용
volumes:
- .:/app
컨테이너 간 통신 문제
여러 개의 컨테이너가 서로 통신해야 하는 경우(예: 웹 서버 컨테이너가 데이터베이스 컨테이너에 접속), 통신이 제대로 이루어지지 않는 문제가 발생할 수 있습니다. 이는 주로 네트워크 설정이나 서비스 이름 확인 문제에서 비롯됩니다.
해결 — Docker 네트워크와 서비스 이름 활용
1. Docker Compose 네트워크 사용:
Docker Compose로 여러 서비스를 정의하면, Compose는 기본적으로 이 서비스들을 위한 브릿지 네트워크를 생성합니다. 이 네트워크 내에서는 서비스 이름(docker-compose.yml에 정의된 서비스 이름)을 사용하여 서로 통신할 수 있습니다. 예를 들어, 웹 서비스에서 데이터베이스 서비스(db)에 접속하려면 mongodb://db:27017/myapp_dev와 같이 서비스 이름을 호스트명으로 사용하면 됩니다.
services:
web:
environment:
MONGO_URI: mongodb://db:27017/myapp_dev # 'db'는 데이터베이스 서비스 이름
db:
image: mongo:4.4
2. 수동으로 Docker 네트워크 생성 및 연결:
Docker Compose를 사용하지 않고 개별 docker run 명령으로 컨테이너를 실행하는 경우, 명시적으로 네트워크를 생성하고 컨테이너들을 연결해야 합니다.
docker network create my_app_network
docker run --name db_container --network my_app_network -d mongo:4.4
docker run --name web_container --network my_app_network -p 80:3000 -d my-web-app
이 경우, web_container에서 db_container로 통신할 때 db_container라는 이름을 호스트명으로 사용할 수 있습니다.
핵심 포인트
Docker 사용 중 발생하는 대부분의 문제는 포트 매핑, 파일 권한, 네트워크 설정과 관련됩니다. 오류 메시지를 주의 깊게 읽고, 관련 설정을 확인하거나 변경하여 해결할 수 있습니다. 특히 Docker Compose는 복잡한 네트워크 설정을 자동으로 처리해 줍니다.
실전 적용
Docker를 이용한 애플리케이션 배포
Docker의 진정한 가치는 애플리케이션 배포 과정의 일관성과 효율성에서 빛을 발합니다. “개발 환경에서는 잘 되는데, 운영 환경에서는 왜 안 될까요?”라는 질문은 더 이상 유효하지 않습니다. Docker 컨테이너는 개발 환경에서 실행되는 방식 그대로 운영 환경에서도 실행될 것을 보장합니다. 이는 CI/CD(지속적 통합/지속적 배포) 파이프라인 구축에 혁혁한 공을 세웠습니다.
CI/CD 파이프라인에서의 Docker
CI/CD 파이프라인에서 Docker는 다음과 같은 방식으로 활용됩니다:
- • 빌드 단계: 소스 코드를 Dockerfile을 사용하여 Docker 이미지로 빌드합니다. 이 이미지는 애플리케이션과 모든 종속성을 포함하므로, 어떤 환경에서든 동일하게 실행될 수 있습니다.
- • 테스트 단계: 빌드된 Docker 이미지를 사용하여 독립적인 컨테이너 환경에서 자동화된 테스트를 실행합니다. 이는 테스트 환경을 표준화하고, 테스트 결과의 신뢰도를 높입니다.
- • 배포 단계: 테스트가 완료된 Docker 이미지를 Docker Registry(예: Docker Hub, AWS ECR, Google Container Registry)에 푸시하고, 운영 서버나 클라우드 환경에서 해당 이미지를 풀(pull)하여 컨테이너로 실행합니다.
클라우드 환경에서의 Docker 배포
2026년에는 대부분의 클라우드 서비스 제공업체들이 Docker 컨테이너 배포를 위한 다양한 서비스를 제공하고 있습니다. 대표적인 예시는 다음과 같습니다:
주요 클라우드 컨테이너 서비스
AWS (Amazon Web Services):