서비스의 흐름 : 기획, 설계, 디자인, 개발, 운영
지속가능성(sustainability) : 서비스를 오랫동안 운영
dev-ops : 반복적인 작업들을 자동화하는 것이 핵심 ( human error를 제거 )
자동화를 위한 추상화 : 핵심적인 개념, 기능을 간추려 내는 것 ( ex. 하나의 명령어 내부에 수많은 API들이 호출됨 )
- 하드웨어 추상화 : VMware( 물리적인 서버는 하나지만 여러개처럼 )
- 서비스 추상화 : container기술인 docker!
- 서비스 인프라를 추상화 : kubernetes
개발흐름 : 물리적인 서버 → VMware → docker → kubernetes
[ VM vs Container ]
- VM : 하드웨어 위에 여러 OS를 올림 = OS단위로 격리
- Container : OS는 하나( 커널 1개 ) → 그 위에 논리적인 형태로 구분( 컨테이너 단위 )
- 앱과 서비스에 대한 부분만 가지고 있으며 커널에 대한 부분은 공유 → 경량화
docker ≠ container
docker는 container를 쉽게 쓰기 위한 서비스( 컨테이너화 플랫폼 )
[ Docker구조 ]
client의 도커 명령어( docker run, docker build, docker pull … )
docker daemon( 도커 백그라운드 프로세스 )이 소켓으로부터 명령어를 받아서 해석하고 실행, 이미지가 없다면 인터넷의 hub 레지스트리에서 다운로드 받아서 실행
[ 컨테이너 구조 ]
컨테이너 = 격리시키는 기술, 리소스를 공유하면서 독립적으로 실행( namespace & cgroups )
리눅스 프로세스(리눅스 명령어로 돌아가는 것)를 추상화한 것!
Docker 이미지 관리
이미지 : 준비물, 많은 서비스를 가지고 있음, 컨테이너라는 실체화를 만드는 도구
이미지 검색
public registry(docker hub)에 등록된 이미지를 검색 ( *offical 여부를 체크 ) -> 이후 활용하여 컨테이너를 만들 수 있다.
docker search 이름
CLI명령 혹은 웹에서도 검색가능
이미지 다운로드
[ 3가지 방식( docker pull ) ]
- REPO : 태그를 명시하지 않을 경우 자동으로 latest버전의 태그로 설정( REPO:latest )
- REPO:tag : 이미지의 특정버전을 tag로 명시
레포지토리 내에 여러 버전의 이미지가 있을 수 있으며, 그 중 특정 이미지를 태그(tag)를 사용하여 구별 - REPO@digest : 중복되지않는 이미지의 고유 값( 해시값 ) → 배포 시에 많이 사용 ( 태그보다 이미지를 구체적으로 지정 )
[ docker pull 옵션 ]
- -a = —all-tags : 태그된 모든 이미지를 다운로드( 거의 안씀 )
- —platform : 이미지를 실행할때 사용할 플랫폼을 명시(설정), 베이스 이미지에 설정된 플랫폼 정보를 검색
docker pull --platform linux/arm64 myapp
- 이미지는 운영체제와 아키텍처(OS/ARC)에 종속적임 ( 특정 운영체제, 아키텍처에 맞게 빌드된다. )
- 멀티 아키텍처 : 하나의 Docker 이미지가 다양한 CPU 아키텍처에서 실행될 수 있도록 하는 기능
- 플랫폼간 작업 : 하나의 애플리케이션이나 서비스가 다양한 하드웨어 플랫폼에서 실행될 수 있도록 하는 작업 ( ARM계열, AMD계열의 CPU 아키텍처 )
[ Tag & Digest ]
- Tag : 가변값( 태그는 하나이지만 이에 해당하는 이미지의 실체는 변경될 수 있음 ) → 변수명과 유사
- latest태그 : 다운로드 시점에 따라 다른 이미지 실체를 가질 수 있음
- 로컬에서 동일한 Tag를 가진 이미지가 존재하는 경우 레지스트리의 것과 교체하지않음 → 태그기반 이미지가 상호충돌이 발생하는 이유
- Digest : 고유값( 이미지와 일대일 대응 ), 변경불가능
이미지 목록보기
docker image list = docker image ls = dock images
- —all(-a) : 이름은 없지만 한번이라도 사용했던 이미지(dangling) & 중간 이미지까지 표시
- —digest : 이미지들의 digest를 보려면 명시
- —filer(-f) : 필터링 조건에 맞는 이미지만 표시
- —no-trunc : 전체 이미지 ID를 상세하게 표시( sha256형식 )
- —quiet(-q) : 이미지 ID만 표기
docker images ubuntu : 우분투라는 이름을 가진 모든 레포지토리를 검색 ( = REPO로 검색 )
- 레포지토리(Repository) : 공용 레지스트리나 개인 레지스트리에서 관리되는 이미지의 저장소 또는 이미지 모음 -> 이미지 이름을 기준으로 구분 / ubuntu라는 레포지토리는 여러 버전의 ubuntu 이미지를 관리하는 저장소( ubuntu:20.04, ubuntu:22.04 .. )
이미지 삭제하기
docker rmi 이미지명 = docker image rm 이미지명
- 여러 이미지를 동시 삭제 가능
- 이미지를 이용하여 컨테이너를 구축한 경우 원칙적으로 삭제 불가 → -f옵션으로 강제 삭제 가능
모든 이미지 삭제하기
docker image prune
모든 dangling 이미지를 삭제하는 명령어
dangling 이미지 : 이름이 없는 이미지 ⇒ digest는 무조건존재, repo와 tag가 없음(none) docker images -f dangling=true
- tag가 다른 이미지로 교체된 경우(보안패치)
- 임시로 사용했던 중간이미지( multi-stage build ) : 이미지 빌드과정에서 생성되는 임시적인 레이어들의 집합
⇒ docker images 명령어를 실행했을, REPOSITORY와 TAG가 <none>값으로 뜸 & IMAGE ID만 존재함( digest도 존재하지만 표기X )
이미지 정보 조회
docker inspect 이름
inspect : Docker 객체(컨테이너, 이미지, 볼륨, 네트워크 등)에 대한 상세한 정보를 출력하는 명령어
구성정보나 속성을 JSON형식으로 확인가능
⇒ 동작방식을 알 수 있음, 내부 리눅스 명령어도 모두 알 수 있음
⇒ 계정정보나 중요정보는 평문으로 넣지 않을 것!!( 탈취가능 )
[ 연습문제 ]
(1) ARM용 Ubuntu 다운로드하기
도커 이미지는 os와 arch에 종속적이다!
이미지는 레이어들의 조합결과물( 변경불가한 특정버전이 지속적으로 추가, 변경사항이 누적됨 )
베이스이미지로부터 변경사항이 쌓인 것을 쓰고 있다.( 교체x )
다운로드 시에 공통되는 부분이 아닌 신규 추가사항을 제공받음
(2) digset를 이용한 다운로드
docker pull
postgres@sha256:a2282ad0db623c27f03bab803975c9e3942a24e974f07142d5d69b6b8eaaf9e2
고유번호 digest를 이용하여 특정 이미지 다운로드 → TAG정보는 없는 것으로 나옴
25개의 layers와 관련된 리눅스 명령어
Docker 컨테이너 관리
컨테이너 실행하기
- 특정 이미지를 run하여 컨테이너를 생성 ( IMAGE는 repo&tag, repo&digest 로 지정가능 )
- run 명령어 : 로컬에 존재하면 그것으로, 없다면 원격저장소에서 찾아서 사용
—name : 이름 지정, 없다면 자동으로 이름지정(과학자 이름??) → 효율적인 관리를 위해 이름지정을 권장함
—d : 백그라운드 실행명령 / 컨테이너가 백그라운드에서 실행되며, 터미널은 즉시 반환
—expose, —publish(-p) : 포트 개방
—rm : 컨테이너에 정의된 작업 종료시 자동으로 삭제 ( 디버깅, 테스트용도에서 사용 )
-it : 컨테이너 프로세스의 터미널 접근( interactive & tty ) = 컨테이너 내부에서 대화식 터미널 세션을 시작함
-v : 컨테이너는 기본적으로 격리됨 → 소통을 위해 볼륨 스토리지를 설정
[ Expose와 Publish의 차이점 ]
같은 cgroup에 속하는 컨테이너들은 같은 네트워크를 할당받아 기본적으로 접근이 가능
( 기본적으로 호스트에서 컨테이너의 네트워크에 접속불가, 다른 컨테이너의 경우 같은 네트워크 범위라면 접속가능 )
- expose : 컨테이너 내에서 특정 포트를 지정(열어줌) → 같은 네트워크의 다른 컨테이너에서 접근경로를 제시
- publish : 외부 네트워크, 호스트에서 접근가능하도록 함 & 포트를 지정
- 호스트 포트와 바인딩 : 호스트포트:컨테이너포트 ⇒ 호스트의 포트를 컨테이너의 포트와 바인딩, 호스트의 해당포트에 접근하면 컨테이너의 해당포트로 연결됨
- p를 통해 호스트에서 내부 컨테이너로 접속 & 외부의 컴퓨터에서도 내부 컨테이너로 접속
[ 포트개방 예시 ]
22.4의 태그를 가진 우분투 이미지를 실행
컨테이너는 일종의 프로세스, 할 일을 마치면 종료됨
80 포트를 이용하여 nginx 서비스하기
로컬에 없음 → 리모트에서 latest태그 이미지의 레이어를 다운로드
- image : 서비스 제공을 위한 모음( 도구, 단위, 패키지 ), base img부터 여러 layer로 구성됨
- container : 실제 서비스가 실행( docker run 명령어 ), local 컴퓨터 내부에서 격리되어 독립적으로 실행( volume, network .. )
IP대역의 네트워크 대역이 다름 = 서로 접근 불가 → -p 옵션은 해당 포트를 통해 외부에서도 접근가능하도록 뚫어둔다는 의미 < 내가 사용할 포트 : 컨테이너 내부에서 사용할 포트 >
container 내부에는 process가 존재, 무언가를 수행중임
container가 살아있다 = main 프로세스가 활동중임
할일이 없다면 죽음(전원off), —rm옵션에 따라 삭제될 수도 있음
본체에서의 PID ↔ 내부에서의 PID ( 커널은 공유하기에 본체에서도 PID확인 가능, 그러나 그 번호가 달라짐 )
격리되어있는 환경으로 삭제된다면 모든 설정도 삭제( 로그 )
attach vs execute
컨테이너 목록보기
컨테이너는 하나의 프로세스로 상태를 가지게 된다
컨테이너가 종료(off)되었다 한들 삭제되지 않는다면 → 이미지는 사용중이라고 인식됨!! ( 컨테이너의 사용 ↔ 이미지의 사용 )
- docker ps : 살아있는 컨테이너만 표시
- docker ps -a : 모든 컨테이너를 표시 ( 전원 off된 것 까지 ), STATUS : Exit(0) = 정상종료
- 이름 지정옵션 -f
- 사용중인 볼륨 확인 -s : 기본 이미지 + 컨테이너 작업으로 사용되는 양
기본적으로 컨테이너는 내부의 main process로 명령 실행 → main 프로세스 종료(exit)시에 컨테이너도 종료됨
main프로세스가 아닌 백그라운드로 명령 실행 → 데스크탑의 exec창에서 명령 사용가능, log기록이 이루어지지 않음
컨테이너 로그 확인하기
docker logs <NAME_OR_ID>
지정한 —name 혹은 conatiner id를 통해 접근 ⇒ 해당 머신 안에서만 고유값
충돌시에는 외부포트를 변경하면됨( 80포트 이미 사용중 )
$ docker run --name clock -d busybox sh -c "while true; do $(echo date); sleep 1; done"
busybox:latest 이미지를 백그라운드로 실행하면서 그 컨테이너 이름을 clock이라고 붙이는데 기본쉘 sh를 열어서 명령줄 문자를 실행 ( tag없음 ⇒ default latest ) & 1초마다 로그가 쌓이게됨
컨테이너 접속하기( 추가명령 )
기본적으로 컨테이너 접속은 막혀있음( 독립적 )
개발환경, 수동제어시에만 접근 ( 전제조건 : 컨테이너가 수행중이어야함 =ON상태 )
2가지 방식 : attach & exec
1) attach 방식
docker attach [OPTIONS] CONTAINER( id, name )
- 접속의 개념 = 실행중인 컨테이너 한정
- STDIN , STDOUT , STDERR 에 접근 = main process에만 접근 → Ctrl+C를 할경우 프로세스가 종료되며 컨테이너도 종료됨
- 쓰지 않는게 좋음
2) exec 방식
docker exec -it [OPTIONS] <ID_OR_NAME> /bin/bash|sh|…
- 접속이 아닌 접근한다는 개념
- main process가 아닌 별도의 자식 프로세스를 생성하여 추가 명령을 수행 → 종료, 중단되더라도 컨테이너는 살아있다
- 임시로 수행하는 프로세스 ⇒ 재 실행시 보존X
- it옵션을 사용한다면 → 터미널을 통해 대화형 방식으로 진행할 것임, 그렇지 않으면 원격으로 명령 실행후 종료
쉘이 없는 경우도 있음( scratch 이미지 )
echo$$ : 수행중인 PID를 출력하는 명령
계속 새로운 프로세스를 만들어서 출력수행 ↔ 하나의 프로세스에서 해당 프로세스 ID를 지속적으로 출력
컨테이너 명령어 실행하기
명령어는 working directory(pwd)기준으로 실행되므로 이 설정이 중요함 ( —workdir 옵션으로 이를 지정 )
컨테이너 종료 & 시작
기존에 만들어두었던 컨테이너를 다시 시작 혹은 종료( 종료명령어 사용시 —rm을 두지 말아야함 )
docker stop <NAME_OR_ID> → docker start <NAME_OR_ID> : main process만 살아남
exec으로 보조 프로세스에서 실행된 것은 사라짐 = 휘발성
수동으로 실행된 프로세스, Dokerfile을 통해 실행되지 않은 프로세스들은 재시작할 경우 살아나지 않음
컨테이너 중지 & 재실행
이와 달리 docker pause <NAME_OR_ID> → docker unpause <NAME_OR_ID> :
exec으로 실행한 모든 명령어들이 살아있음
컨테이너 삭제
가장 바람직한 것은 컨테이너 종료후 rm을 수행하는것 → 그러나 -f으로 강제종료도 가능
컨테이너 리소스 사용량 조회
배포 직전 서비스의 특성을 체크 ( 네트워크를 많이 사용하는가? 디스크를 많이 사용하느가? ), 적절한 서버를 세팅하는데 중요한 정보를 제공
연습문제
interacive하게 수행
Non-interactive하게 수행
[실습] PostgreSQL DB에 Table 생성하기
API 서버 + config(설정값) ⇒ service instance( service ) 이러한 흐름과 같이
Image(기본틀) + 옵션-e(환경변수) ⇒ container( service ) : 환경변수가 주입된 상태에서 실행된다. 구동하기 위한 환경변수가 주입되어야 실행, 아니라면 자동종료( 실행하다가 스크립트가 멈춤 )
doker run -e 변수명=값 image
우분투버전 bullseye위에 설치된 postgres 16ver을 설치
- main 프로세스에서 psql_db 스크립트를 돌린다( DB운영중 )
- main process는 DB를 운영중이므로 터미널 작업불가, exec를 통해 터미널을 열기( attach하면 터미널이 main이 되면서 DB구동이 종료됨 ) → PostgreSQL 접속
main외의 프로세스로 터미널을 실행 → 이거 꺼도 컨테이너는 종료되지 않음, DB스크립트가 실행중임
DB자료는 컨테이너에 저장 → 컨테이너를 삭제후 다시 이미지를 로드하면 데이터가 손실 ↔ stop후 다시 start하면 데이터 유지( main 프로세스의 값 유지 )
Docker 이미지 생성하기
이미지 생성하기
dockerfile을 이용하여 이미지를 빌드하는 작업
git과 유사함 : 변경상이 기록됨 ( commit : 변경불가한 이미지 )
- Image layer : 모든 층이 변경불가 = read only
- base Image : 변경상이 시작되는 지점 ( ubuntu등의 OS, scratch, alpine …. ⇒ 기본은 scratch )
doker build 옵션 path
- -f 옵션 : 사용할 Dockerfile의 경로를 지정, 지정하지 않으면 경로에서 파일이름이 Dockerfile인 것을 사용함
- path : Dockerfile내 상대경로들은 입력된 path를 기준으로 계산됨 = build context : 빌드할때 사용할 파일들과 리소스를 포함하는 디렉토리
- —platform : 명시하지 않으면 현재 호스트에 맞는 OS/arch기반으로 만들어짐, 이미지에서부터 이를 설정
- --no-cache : 모든 레이어를 새로 생성 & 저장되지 않음
이미지의 build의 과정 = read only layer가 쌓이고 캐시에 저장됨
- image layers ( 이미지를 구성하는 레이어들 ) = read only layers가 묶음으로 처리
- 캐시에 저장되어 공유가능( 마치 git에서 다른 브랜치의 이전내역이 공유되는 것과 같음 )
- overlay file system : 베이스 반대방향부터 찾아가며 해당 이미지를 찾아간다( 버전찾기 )
- container layer = 컨테이너의 볼륨이 저장
- container를 삭제했다 = container layer를 삭제했다는 의미 = 컨테이너 생성시 쓰기용 레이어가 하나더 추가됨
Dockerfile
ARG : 이미지 빌드를 수행하는 동안에만 저장할 변수
FROM : 어떠한 이미지로부터 변경사항을 저장할 것인가
- 베이스 이미지를 지정, 하나이상의 FROM이 반드시 명시되어야함
ubuntu/debian, alpine, disroless, scratch : 보안성과 사용성은 상반됨 - FROM이 두번이상 쓰이게 되면 multi-stage build가 됨
LABEL : 이미지 관리용 태그, 만든사람, 저작권 정보
ENV : default값을 선언, 프로그램에서 사용할 환경변수
ADD : 외부 파일을 넣음, 경로(링크→외부가능) + 넣을 이름
COPY : 외부 파일을 넣음, [ 로컬머신에 있는경로(PATH기준 상대경로) + 컨테이너 내의 경로(절대경로) ]
WORKDIR : 작업시작경로
EXPOSE : 알려주는 용도 comment
RUN : 이미지를 만들때( build시에 ) 수행하는 명령어, 만드는 과정에서 쓰는 명령어, 이미지 만들어진 이후에 사용하지 않음 ( 캐시 및 apt-get update가 있는 경우 그 시점에서 실행되니까 문제 발생가능 )
CMD : 오버라이드 가능한 명령어 docker run 이미지 이름 + 실행명령어 → 여기서 오버라이딩하는 것임
ENTRYPOINT : 변경불가한 진입점, 시작점
=> 도커파일(변경사항)의 각 줄이 레이어로 작성된다.
* 변수 지시어
- ARG : 빌드시에만 사용 → 이후에는 사용불가 ⇒ FROM을 제어가능, 유일하게 FROM앞에 사용가능
- ENV : 어플리케이션(컨테이너화된 상태)에서 사용 ( + 빌드단계에서도 사용가능 )
* 파일 이동/복사 명령어 : 특정파일 또는 디렉토리를 이미지로 옮기는 명령어 ( * 절대경로는 root(/)에서 시작→ 모든 환경에서 다를 위험, 상대경로는 현위치(.)에서 시작 )
- ADD <src> <dest> : 외부파일을 복사가능( HTTP, git … )
- COPY <src> <dest> : 로컬머신의 파일을 옮기는데 주로 사용됨, 다른이미지에서 가져오기가 가능함 ( —from : 다른이미지 )
* 수행할 명령어를 지정
- RUN : build시( 이미지 제작과정 ) 작동( 빌드목적 ) 구동을 위한 패키지 설치목적의 명령어들 : apt-get update, pip install, npm install
- CMD : 컨테이너 실행시점에서 작동 ( 서비스 수행목적 ), 변경가능( override ) ⇒ 여러 개일 경우 가장 마지막 명령으로 대체됨( 베이스 이미지에도 CMD가 존재하기에 )
argument : 옵션, 인자 = 사용자가 원하는 서비스를 실행 - ENTRYPOINT : 컨테이너 실행시점에서 작동 ( 서비스 수행목적 ), 변경불가능 ( 고정 ) ⇒ 여러 개일 경우 가장 마지막 명령으로 대체됨( 베이스 이미지에도 EP가 존재하기에 )
executable : 실행주체, 진입점 = 제작자의 의도 ( ex. docker, git .. )
⇒ ENTRYPOINT + CMD 의 조합으로 고정된 명령어 & 가변적인 명령어의 수행이 가능함 ( docker image list에서 docker=EP(고정), image+list=CMD(변경) )
[ 많이 사용하는 base 이미지 ]
이미지의 용량은 매우 중요함 ( 여러 곳에서 pulling한다고 하면 )
- scratch 이미지 : 바이너리를 실행하기 위한 최소한의 이미지 ⇒ 빠른 속도
- alpine linux : 저용량 리눅스
- distroless : 쉘(터미널)이 없음 → 작업불가
- 우분투는 그 자체가 1GB가 넘는데 잘 안씀
각각 debian, alpine, scratch를 이용하여 빌드한 시간, 빌드에 소요되는 시간도 모두 상이함 ( 이미지의 무게가 다름 )
[ cache ]
: 빌드시에 불필요한 리소스 작업을 감소시킨다. 동일한 명령어가 들어왔다면 수행하지 않고 기존의 이미지를 재사용한다.
- 새로운 이미지 빌드할때 기존의 레이어를 활용한다
- 캐시의 사용여부 : 기존 명령어와 동일하다 & 전후관계가 동일하다 ( 둘다 만족해야함 )
input은 2가지가 됨 = 앞선 레이어의 상황(base) + 수행명령인자 ( base가 달라진다면 명령이 동일하더라도 다른 명령으로 인식 ) - ARG를 사용하면 캐시미스가 많이 발생함 → 인자가 달라짐!!
- 명령어의 순서도 중요함 : 변경사항이 적은 것부터 적고 변경이 많은 것을 나중에 적기 ⇒ 캐시를 재사용할 확률을 높인다 ( ex. 소스코드를 COPY하는 작업은 나중에 → 자주 변경 , 패키지 다운받는 작업은 앞에 ) ( 소스코드 COPY가 달라진다진다면 그 위의 레이어들은 모두 변경됨 )
COPY가 달라질때 캐시를 못쓴다는게 경로가 아니라 내용만 달라져도 다르게 인식하는건가??? 맞음, checksum으로 비교하여 다른 레이어로 인식하고 캐시를 사용하지 않음 - RUN 명령어를 작게한다 ( RUN apt-get update && apt-get upgrade )
Multi-stage builds
# 'golang:1.19-alpine' 이미지를 이용하여 Go Applicatoin을 컴파일
FROM golang:1.19-alpine AS build
WORKDIR /app
COPY src ./
RUN CGO_ENABLED=0 go build -o main
# 위에서 컴파일한 소스코드만 'Scratch' 이미지로 가져와 실행
FROM scratch AS release
COPY --from=build /app/main /app/
WORKDIR /app
CMD ["/app/main"]
stage별로 빌드를 수행( 여러 base image를 사용하여 단계별로 가볍게 만듬 )
run-time dependency와 build-time dependancy가 상이함 = 빌드와 실행을 분리( alpine을 이용하여 빌드 → scratch를 이용하여 실행 )
- apline은 scratch보다 무겁지만 빌드를 위한 최소환의 환경, 라이브러리를 갖추고 있음 ⇒ 바이너리 파일만을 실행시키기 위한 이미지를 생성
- scratch는 실행하기에는 가볍지만 빌드하기에는 불가능한 환경으로 추가적인 수동설치가 필요함 ⇒ 바이너리 파일을 실행하기만 함
[ 실습 ] 우분투 컨테이너 내부에 도커를 설치
install_docker_engine.sh : 우분투 환경 내부에 도커 엔진을 설치하는 스크립트 파일
apt-get update && apt-get upgrade
apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL <https://download.docker.com/linux/ubuntu/gpg> | gpg --dearmor -o
/etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \\
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg]
<https://download.docker.com/linux/ubuntu> \\
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \\
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update && apt-get upgrade
Dockerfile : 실제 우분투 22.04에서 스크립트를 내부에 저장 → RUN영역에서 권한 추가 & 스크립트 실행
FROM ubuntu:22.04
RUN mkdir -p /scripts
COPY install_docker_engine.sh /scripts
WORKDIR /scripts
RUN chmod +x install_docker_engine.sh
RUN ./install_docker_engine.sh
RUN apt-get install -y docker-ce docker-ce-cli
docker build -f Dockerfile2 -t cloudwave:base.v1 .
[실습] Arg 를 이용하여 base 이미지 변경하기
- docker build 명령어에서 --build-arg를 사용하여 ARG에 해당하는 값을 CLI명령으로 주입
- command line에서 매개변수를 변경하여 빌드하며 여러 버전의 이미지 생성가능
ARG OS
FROM golang:${OS}
ENV BASE=${OS}
FROM OS
WORKDIR /app
COPY src ./
RUN CGO_ENABLED=0 go build -o main
CMD ["/app/main"]
# Base 이미지에서 사용하는 OS를 ARG로 받습니다.
ARG OS
# 입력받은 OS를 기반으로 golang 이미지를 설정합니다.
FROM golang:${OS} AS builder
# 환경변수를 설정
ARG OS
ENV BASE=${OS}
# 작업 디렉토리 설정
WORKDIR /app
# 소스 코드 복사
COPY src ./
# 애플리케이션 빌드
RUN CGO_ENABLED=0 go build -o main
# 최종 이미지 단계
FROM ${OS}
# 작업 디렉토리 설정
WORKDIR /app
# 빌드된 바이너리 복사
COPY --from=builder /app/main .
# 실행 명령어 설정
CMD ["/app/main"]
이때 명령인자로 받는 OS는 go lang컴파일을 지원하는 것이어야함
즉 사용하는 베이스 이미지는 golang:특정os/arch ⇒ os/arch가 가능한 것을 미리 확인해 둘것
docker build --build-arg OS=1.24-rc-bullseye -f Dockerfile3 -t cloudwave:base.arg .
docker run -d -p 90:80 cloudwave:base.arg
curl 127.0.0.1:90
Docker 이미지 업로드 하기
기본 registry는 docker hub로 지정됨 ⇒ 다른 레지스트리를 원한다면 repo앞에 붙여주기
(1) 이미지 이름(태그) 변경하기
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
이미지가 복제되는 것이 아니라 이름이 하나 더 생성되는 것이다.
수정 시 자동으로 이름이 넘어감(digit는 상이함) → dangling image에 대한 tag 변경이 필요함
- 레지스트리에 업로드하기 위한 이름 형식 : 유저명(namespace)/레포명:tag명
tag명령어의 결과 : 동일한 이미지에 이름을 하나더 추가함( 동일한 Image ID, 다른 이름 )
(2) 레지스트리 로그인하기
docker login [OPTIONS] [SERVER[:PORT]]
-p로 password입력가능
-u로 username지정가능
(3) 이미지 업로드 하기
- docker push( ↔ docker pull ) : 없는 것들만 비교해서 추가 및 전달 = 레이어기반으로 동작
- 풀 이미지 포맷(push형식) : **도메인:**포트(URL)/[namespace]/**레포명:tag명**
- 레지스트리 주소 기본값은 docker.io ( Docker Hub ) 이외 AWS ECR, Google Container Registry는 직접 명시 해줄 것
# Example - ECR
.dkr.ecr.ap-northeast-2.amazonaws.com/cloudwave:v1
# Example - private registry
[my.registry.com:5000/cloudwave/spring:v1](<http://my.registry.com:5000/cloudwave/spring:v1>)
'CLOUDWAVE' 카테고리의 다른 글
Kubernetes Basic : Cluster, Node, Pod, Label&Annotation, Namespace ( 25.01.09 ) (0) | 2025.01.15 |
---|---|
Abstraction : Container, MSA ( 25.01.08 ) (0) | 2025.01.15 |
Docker Compose practice : compose file ( 25.01.06-07 ) (0) | 2025.01.14 |
Docker Compose practice : compose CLI ( 2025.01.03 ) (0) | 2025.01.14 |
Dokcer Practice : Docker Volume, Docker Network, Docker Advance ( 2025.01.02 ) (0) | 2025.01.14 |