1. 기본 문법#
두 명령어의 문법은 거의 동일하지만 동작 방식에 큰 차이가 있습니다:
1
2
3
4
5
|
# COPY - 순수한 파일 복사, 추가 처리를 하지 않음
COPY [--chown=<user>:<group>] <src>... <dest>
# ADD - 자동 압축 해제 및 원격 URL을 지원하지만 예측 불가능한 동작 가능
ADD [--chown=<user>:<group>] <src>... <dest>
|
2. 압축 파일 자동 해제#
ADD는 로컬 압축 파일을 자동으로 해제하지만 COPY는 그렇지 않습니다:
1
2
3
4
5
6
7
|
# ADD는 .tar.gz를 자동 해제
ADD app.tar.gz /opt/app/
# 결과: /opt/app/ 아래에 압축이 해제된 내용
# COPY는 파일 자체만 복사
COPY app.tar.gz /opt/app/
# 결과: /opt/app/app.tar.gz는 원본 압축 파일
|
지원하는 압축 형식: .tar, .tar.gz/.tgz, .tar.bz2, .tar.xz
압축 파일을 그대로 복사하고 해제하지 않으려면 반드시 COPY를 사용해야 합니다.
3. 원격 URL 다운로드#
ADD는 URL에서 직접 파일을 다운로드할 수 있지만 COPY는 지원하지 않습니다:
1
2
3
4
5
|
# ADD는 원격 파일 다운로드 가능 (하지만 권장하지 않음)
ADD https://example.com/app.tar.gz /opt/
# COPY는 URL을 지원하지 않음
COPY https://example.com/app.tar.gz /opt/ # 오류 발생!
|
ADD로 원격 파일을 다운로드하는 대신 RUN + curl을 사용하는 것을 추천합니다. ADD 다운로드는 빌드 캐시를 활용할 수 없고, 오류 처리가 불가능하며, 무결성 검증도 할 수 없기 때문입니다.
1
2
3
4
|
# 추천: RUN + curl
RUN curl -fsSL -o /tmp/app.tar.gz https://example.com/app.tar.gz \
&& tar -xzf /tmp/app.tar.gz -C /opt/ \
&& rm /tmp/app.tar.gz
|
4. 디렉터리 자동 생성#
두 명령어 모두 존재하지 않는 중간 디렉터리를 자동으로 생성합니다:
1
2
3
4
5
6
|
# /etc/myapp/config/가 존재하지 않으면 자동 생성
COPY app.conf /etc/myapp/config/
ADD app.conf /etc/myapp/config/
# 수동으로 mkdir 불필요
# RUN mkdir -p /etc/myapp/config ← 불필요
|
5. 빌드 캐시 동작#
1
2
3
4
5
|
# COPY - 파일 내용을 엄격하게 비교, 내용이 변경되어야 캐시 무효화
COPY config/app.conf /etc/app/
# ADD - 압축 파일 내용이 동일하면 캐시 유지
ADD app.tar.gz /opt/app/
|
| 상황 |
COPY |
ADD |
| 파일 내용 변경 |
캐��� 무효화 |
캐시 무효화 |
| 파일 메타데이터 변경 |
캐시 무효화 |
캐시 무효화 |
| 압축 파일 내용 동일 |
N/A |
캐시 유지 |
6. 기능 비교#
| 기능 |
COPY |
ADD |
| 로컬 파일 복사 |
✅ |
✅ |
| 디렉터리 복사 |
✅ |
✅ |
| 와일드카드 지원 |
✅ |
✅ |
| 디렉터리 자동 생성 |
✅ |
✅ |
| 압축 파일 자동 해제 |
❌ |
✅ |
| 원격 URL 지원 |
❌ |
✅ |
| 의미 명확성 |
✅ 높음 |
❌ 낮음 |
| 사용 권장 |
✅ 우선 사용 |
⚠️ 특정 상황 |
7. 사용 사례#
COPY에 적합한 경우:
1
2
3
4
5
6
7
8
9
|
# 설정 파일 복사
COPY nginx.conf /etc/nginx/nginx.conf
# 애플리케이션 코드 복사
COPY src/ /app/src/
COPY package.json /app/
# 멀티스테이지 빌드에서 바이너리 복사
COPY --from=builder /app/build/app /usr/local/bin/
|
ADD는 자동 압축 해제가 필요한 경우에만 사용:
1
2
3
4
5
|
# ADD의 적절한 사용
ADD node-v18.17.0-linux-x64.tar.gz /usr/local/
# 일�� 파일에는 ADD를 사용하지 마세요
ADD app.conf /etc/app/ # ← COPY로 대체
|
8. 모범 사례#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# 규칙 1: 기본적으로 COPY 사용
COPY requirements.txt /app/ # ✅
ADD requirements.txt /app/ # ❌ 불필요
# 규칙 2: 압축 해제가 필요할 때만 ADD 사용
ADD node-v18.tar.gz /usr/local/ # ✅ 압축 해제 필요
# 규칙 3: 원격 파일은 RUN + curl 사용
RUN curl -fsSL -o /tmp/app.tar.gz https://example.com/app.tar.gz \
&& tar -xzf /tmp/app.tar.gz -C /opt/ \
&& rm /tmp/app.tar.gz # ✅
ADD https://example.com/app.tar.gz /opt/ # ❌
# 규칙 4: .dockerignore로 컨텍스트 축소
# .dockerignore
# .git
# node_modules
# *.md
# .env
# 규칙 5: COPY 순서를 적절히 배치하여 캐시 활용
COPY package.json package-lock.json ./ # 의존성 먼저 복사 (변경 적음)
RUN npm ci --production
COPY . . # 코드 나중에 복사 (변경 많음)
|
9. 흔한 함정#
1
2
3
4
5
6
7
8
9
10
|
# 함정 1: 의도치 않은 자동 압축 해제
ADD app.tar.gz /opt/app/
# 파일을 복사했다고 생각했지만 실제로는 디렉터리로 해제됨
# 함정 2: 원격 파일 캐시 불가
ADD https://github.com/user/repo/releases/download/v1.0/app.tar.gz /tmp/
# 매 빌드마다 다시 다운로드
# 함정 3: 권한 문제
COPY --chown=app:app src/ /app/src/ # 소유자 지정
|
10. 선택 결정#
1
2
3
4
5
6
7
|
파일 복사가 필요한가?
├── 로컬 압축 파일이며 해제가 필요한가?
│ └── ADD 사용
├── 로컬 일반 파일인가?
│ └── COPY 사용
└── 원격 파일인가?
└── RUN + curl 사용
|