도커는 리눅스 응용 프로그램들을 프로세스 격리 기술들을 사용해 컨테이너로 실행하고 관리하는 오픈 소스 프로젝트이다.
컨테이너 기반 오픈소스 가상화 플랫폼라고 보면 된다.

도커 컨테이너는 일종의 소프트웨어를 소프트웨어의 실행에 필요한 모든 것을 포함하는 완전한 파일 시스템 안에 감싼다.
여기에는 코드, 런타임, 시스템도구, 시스템 라이브러리 등 서버에 설치되는 무엇이든 아우른다. 이는 실행 중인 환경에 관계 없이 언제나 동일하게 실행될 것을 보증한다.
출처 : 도커 공식 홈페이지
| 구분 | 설명 |
|---|---|
| 이미지 | 서비스 운영에 필요한 서버 프로그램, 소스코드 및 라이브러리, 컴파일 된 실행 파일을 묶는 형태 -> 도커 이미지 즉, 특정 프로세스를 실행하기 위한 모든 파일과 설정값을 지닌 파일들의 묶음이다. |
| 컨테이너 | 이미지를 실행한 상태, 응용 프로그램의 종속성과 함께 응용프로그램 자체를 패키징 or 캡슐화 하여 격리된 공간에서 프로세스를 동작시키는 기술을 의미한다. |
| 명칭 | 로고 | 설명 |
|---|---|---|
| 도커 컴포즈(Docker compose) | ![]() | 멀티 컨테이너 도커 애플리케이션을 정의하고 실행하는 도구이다. YAML 파일을 사용하여 애플리케이션의 서비스를 구성하며 하나의 명령을 가지고 모든 컨테이너의 생성 및 시작 프로세스를 수행한다. |
| 도커 스웜(Docker swarm) | ![]() | 도커 컨테이너의 네이티브 클러스터링 기능을 제공하며 도커 엔진을 하나의 가상 도커 엔진으로 탈바꿈시킨다. 도커 1.12 이상부터 Swarm 모드가 도커 엔진에 통합되어 있다. |
이전에 덧셈에 관련된 간단한 CORS 문제를 해결도 했고, 도커를 적용할 겸 backend, frontend 프로젝트에 Dockerfile 이름으로 된 파일을 만들어서 아래에 해당하는 내용을 작성해줄 것이다.
# 빌드 스테이지 시작
# gradle 이미지 가져오기 (빌드 스테이지를 build라는 이름으로 설정)
FROM gradle:7.6.1-jdk17-alpine AS build
# 컨테이너 내부 (alpine 리눅스 환경)의 app폴더로 설정
WORKDIR /app
# 현재 디렉토리 내의 모든 파일과 폴더를 컨테이너의 /app 디렉토리로 복사 (프로젝트에 있는 모든 파일을 옮기게 된다. 현재 위치는 프로젝트 폴더 위치니까)
COPY . .
# gradle을 사용하여 프로젝트를 빌드 (daemon 프로세스 사용 안 함) --no-daemon 부분은 필수는 아니다. daemon으로 인해 오류가 생길 것을 방지한 것
RUN gradle clean build --no-daemon
# 2. 실행 스테이지 시작.
# openjdk 17 버전의 이미지를 가져와 JVM 환경 구축
FROM openjdk:17-alpine
# 2-1. 빌드를 미리 수동으로 프로젝트에서 하고 이미지를 구축할 시
#COPY build/libs/*.jar app.jar // 1~7번 라인이 아니었으면 해당 주석 라인만 사용했지만, 수정 과정을 거치면서 주석처리
# 2-2. 빌드를 따로 수동으로 하지 않고 이미지를 구축할 때 (docker build)
COPY --from=build /app/build/libs/*.jar ./
# *.jar 파일을 나열하고 그 중에서 plain은 이 포함된 것을 제외한 줄을 선택해 app.jar로 변경한다.
RUN mv $(ls *.jar | grep -v plain) app.jar
# app.jar를 리눅스 환경에서 실행 (스프링 부트 서버 실행) -> 7777 포트
ENTRYPOINT ["java", "-jar", "app.jar"]
FROM node:lts-alpine
# curl 설치(client-url): 필수는 아님(postman 같은 것)
RUN apk add --no-cache curl
WORKDIR /app
COPY . ./
RUN npm install
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
백엔드 프로젝트와 프론트엔드 프로젝트가 속한 프로젝트에서 docker-compose.yml을 통해서 해보려고 한다.
우선은 위의 파일을 통해서
docker build -t jojehuni/sw_vue_project .docker build -t jojehuni/sw_boot_project .를 전체 터미널 창을 통해 이미지를 만들고 컨테이너도 만들어줄 것이다.
이전 게시글에서 다뤘던 CORS에 이어서
App.vue
<template>
<div class="plus">
<h1>덧셈 기능 만들기</h1>
<label>num1: </label><input type="text" v-model="num1">
<label>num2: </label><input type="text" v-model="num2">
<button @click="sendPlus">더하기</button>
<hr>
<p>`{{ num1 }} + {{ num2 }} = {{ result }}`</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const num1 = ref(0);
const num2 = ref(0);
const result = ref(0);
const sendPlus = async() => {
// const response = await fetch(`http://localhost:7777/plus?num1=${num1.value}&num2=${num2.value}`);
// const response = await fetch(`http://localhost:5173/api/plus?num1=${num1.value}&num2=${num2.value}`);
// config를 통해 cross origin이 아닌 same origin이 된다. sop를 만족
// const response = await fetch(`http://localhost:8056/plus?num1=${num1.value}&num2=${num2.value}`);
// 위의 코드는 sw_boot_project2를 할 때 했던거였고, 다시 백엔드에서 cors를 해결하지 않고 프론트에서 하기 위해 주석
// 8055 컨테이너 (8055:7777로 된 백엔드 서버 컨테이너)로 요청 시 (백엔드에서 cors 처리를 했을 경우)
const response = await fetch(`http://localhost:8055/plus?num1=${num1.value}&num2=${num2.value}`); // 백엔드에서 cors 처리를 했다면 이 코드가 된다.
// 프론트에서 cors 처리를 하고자 하는 경우(프론트 프로젝트가 컨테이너가 아닌 상태)
const response = await fetch(`http://localhost:8011/api/plus?num1=${num1.value}&num2=${num2.value}`);
// 프론트에서 cors 처리를 하고자 하는 경우(프론트 프로젝트가 컨테이너인 상태)
const response = await fetch(`http://localhost:8011/api/plus?num1=${num1.value}&num2=${num2.value}`);
const data = await response.json();
result.value = data.sum;
}
</script>
<style scoped>
div.plus {
align-items: center;
}
</style>
백엔드에서 cors를 하는 것을 권장하지만 프론트에서 하는 경우 아닌 경우 등 몇 가지를 적용했었다.
(저 주석이 안 달린 3개의 코드를 백엔드에서 CORS 처리를 해제한 채로 번갈아가면서 해보면 알 수 있다.)
해당 내용보다 쿠버네티스를 적용하면서 백엔드에서 CORS 하는 형태로 적용해볼 것이기에 예제를 전부 작성하지는 않고 넘어가며 이전 게시글이 더욱 중요하되, 다음 정리를 위해 추가를 해본다.
이후에 Ingress도 추가하면서 더 다뤄볼 것이고 그러면서 수정할 내용도 생길 것이지만 추가하며 글을 마친다.