해당 스터디는 90DaysOfDevOps
https://github.com/MichaelCade/90DaysOfDevOps
를 기반으로 진행한 내용입니다.
Day 23 - SQL Server 2022 on Linux Containers and Kubernetes from Zero to a Hero!
Docker는 어플리케이션을 컨테이너라는 격리된 환경에 담아 실행하는 프로그램이며, 컨테이너를 위한 런타임을 제공한다.
이미지 (Image) :
컨테이너 (Container) :
레지스트리 (Registry) :
Container는 '상태가 없는 (Stateless)' 특성을 가진다.
Container 내부의 프로세스가 종료되면 컨테이너는 멈추고, 데이터는 사라진다.
따라서, Container는 데이터를 영구적으로 보존해야 하는 DB 환경에는 적합하지 않다.
이러한 문제점을 해결하기 위해 Host 컴퓨터의 저장공간을 Container에 연결하는 Volume을 사용한다.
이를 통해 Container가 사라져도 데이터는 Host에 영속적으로 안전하게 보관된다.
DB 백업과 데이터 파일은 반드시 이처럼 Container 외부에 존재해야 한다.
SQL Server 컨테이너는 격리된 환경에서 실행되는 SQL Server 컨테이너 이미지의 인스턴스이다.
SQL Server 컨테이너 이미지는 리눅스 (레드햇, 우분투 등) OS 위에 SQL Server (Ver 17, 19, 22등) 가 사전 설치된 패키지를 의미한다.
해당 이미지에는 SQL Server의 핵심 엔진과 도구 등 실행에 필요한 최소한의 바이너리 (bin, lib)만 포함되어있다.
❓그렇다면 SQL Server Container를 사용하는 이유가 뭘까?
VM 환경과 비교하였을 때, 컨테이너가 제공하는 명확한 이점으로 인해 사용한다.
VM 환경에서는 VM 인스턴스의 리부트 시점과 영향에 대한 고민, 다른 개발자 환경에 영향을 끼칠 수 있다는 불안과 고민이 항상 존재한다.
하지만, Container는 모든 개발자가 각자 격리된 자신만의 Container를 사용하므로 이러한 고민과 문제들이 해결된다.
SQL Server는 단순한 DB가 아니라 '데이터 관리 시스템'이다.
컨테이너 환경의 이점과 SQL Server 자체가 가진 기능들을 통해 개발과 운영 환경에 사용한다.
도커는 클라이언트-서버 구조로 작동하는 어플리케이션이다.
Build (빌드): Dockerfile 설명서를 바탕으로 docker build 명령어를 실행하여 새로운 Container Image를 생성
Push (푸시): 생성된 Image를 docker push 명령으로 도커 레지스트리에 업로드하여 공유 및 백업
Pull (풀): 레지스트리에 있는 이미지를 docker pull 명령으로 로컬 서버에 다운로드
Run (런): 로컬에 받아진 이미지를 docker run 명령으로 실행하여 Container 실행
Docker는 현재 무료인 '커뮤니티 에디션 (CE)'과 유료 기술 지원이 포함된 '엔터프라이즈 에디션(EE)'으로 나뉜다.
특히, 윈도우 11 환경에서 Docker Desktop을 설치할 때 'WSL (Windows Subsystem for Linux)'를 백엔드로 사용하는 것이 권장된다.
WSL은 윈도우 내에서 가벼운 Linux VM을 생성하며, Docker Desktop은 해당 VM 내부에서 Docker Daemon을 실행하여 리눅스 Container를 관리한다.
하지만, Docker desktop의 직원 수 250명 이상의 기업에서 상업적 용도로 사용할 경우의 유료화로 인하여 '파드맨 (Podman)'이라는 플랫폼이 대안으로 제시되었다.
Podman은 레드햇에서 개발하였으며, 현재 윈도우용 파드맨 데스크톱은 무료로 사용할 수 있다.
또한, 백그라운드에서 항상 실행되는 데몬 (에이전트) 없이 작동하기 때문에 Docker보다 더 안전한 아키텍처로 평가받기도 한다.
WSL은 Docker의 기반 기술일 뿐만 아니라, 그 자체의 플랫폼으로도 개발 환경을 제공한다.
wsl --install
해당 명령어로 간단히 설치할 수 있으며, WSL 내에 직접 MySQL, PostgresSQL, SQL Server 등을 설치하여 Docker의 대안으로 활용할 수도 있다.
추가적으로, Windows 환경에서 WSL (Windows Subsystem for Linux)를 백엔드로 사용하는 Docker Desktop의 경우, 이미지와 데이터는 Windows 파일 탐색기에서 직접 접근할 수 없는 특별한 위치에 저장된다.
C:\Users\<사용자>\AppData\Local\Docker\wsl
경로 아래의 data와 distro 폴더 내에 저장\\wsl.localhost\
경로를 통해 접근해야함)docker info 명령어는 도커 엔진의 버전, 스토리지 드라이버 (overlay2 등), 컨테이너 수 등 시스템 전반의 정보를 보여준다.
Windows에서 이 명령을 실행하면 종종 warning: no swap support 라는 경고 메시지가 나타날 수 있다.
하지만, 해당 경고는 WSL 백엔드를 사용하는 환경에서는 파일 마운팅과 관련된 것으로, 실제 운영에 영향을 주지 않는 중요하지 않은 경고이므로 걱정할 필요가 없다고 한다.
docker search <이미지 이름>
# 전체 태그 목록을 변수에 저장
PS C:\Users\<사용자명>> $allTags = Invoke-WebRequest -Uri 'https://mcr.microsoft.com/v2/mssql/server/tags/list' | ConvertFrom-Json
# 저장된 목록에서 '22'가 포함된 태그만 필터링
PS C:\Users\<사용자명>> $allTags.tags | Where-Object { $_ -like '*22*' }
Docker Images
docker rmi <이미지 ID 또는 이름>
# 현재 실행 중인 Container 조회
docker ps
# 중지된 컨테이너까지 모두 조회
docker ps -a
docker stop <컨테이너 ID 또는 이름>
docker rm <컨테이너 ID 또는 이름>
docker stop $(docker ps -aq)
docker rm $(docker ps -aq)
docker rmi $(docker images -q)
docker volume prune
docker inspect <이미지 ID>
해당 명령어를 사용하여 이미지의 Label, 환경 변수 등 상세한 내부 정보를 JSON 형식으로 확인할 수 있다. (ex. SQL Server Image의 정확한 버전 정보를 레이블 섹션에서 찾아낼 수 있음.
Image를 pull 할때 '콘텐츠 다이제스트 (Content Digest)'라는 고유한 해시 (hash) 값이 함께 제공된다.
docker inspect 결과의 RepoDigests 필드에서 해당 값을 확인할 수 있으며, 이를 통해 User가 다운로드한 Image가 레지스트리에 있는 원본과 정확히 동일하고 변조되지 않았음을 보장받을 수 있다.
이미지 매니페스트는 이미지의 구성 요소 (Layer, 아키텍처 등)을 설명하는 명세서와 같은 파일이다.
해당 기능은 인터넷 연결이 없는 폐쇄망 환경에서 이미지를 옮겨야 할 때 유용한 기능이다.
Docker Container의 File System은 '유니온 파일 시스템 (Union File System)'이라는 방식으로 동작한다.
Union File System이란, 여러 개의 다른 디렉토리를 하나의 디렉토리처럼 보이도록 통합 (Union) 하고 겹쳐서 보여주는 기술이다.
이는 Image의 효율적인 관리와 Container의 빠른 생성을 가능하게 한다.
docker pull 시 여러 개의 Pull complete 메세지를 확인할 수 있는데, 여러 개의 Layer를 다운로드 하는 과정이다.
읽기 전용 이미지 레이어 (Read-only Image Layers):
쓰기 가능 컨테이너 레이어 (Writable Container Layer):
Copy-on-Write(CoW)는 "쓸 때 복사한다"는 의미로, 읽기 전용인 이미지 레이어의 파일을 컨테이너가 어떻게 수정할 수 있는지 설명하는 메커니즘이다.
쓰기 요청 발생: 컨테이너 내부의 프로세스가 특정 파일 (ex. 설정 파일)을 수정하려고 함.
(해당 파일은 현재 읽기 전용 이미지 레이어에 존재)
파일 위치 확인: Docker는 먼저 최상위의 쓰기 가능 레이어에 해당 파일이 있는지 확인함.
(처음에는 파일이 없음)
파일 복사 (Copy): Docker는 하위의 읽기 전용 레이어에서 원본 파일을 찾아, 그 파일의 복사본을 만들어 최상위의 쓰기 가능 레이어로 가져옴. (Copy 과정)
복사본 수정 (Write): 컨테이너는 쓰기 가능 레이어에 있는 복사본 파일에 변경 사항을 기록함. (원본 파일은 그대로 보존된 채, 컨테이너는 수정된 버전을 사용하게 됨)
앞서 설명한 CoW 방식은 File 단위로 동작하기 때문에 RDBMS와 같은 환경에서는 비효율적이다.
예를 들어, 10GB짜리 거대한 DB 파일이 있다고 가정시, UPDATE 쿼리로 몇 KB의 데이터만 변경되어도 CoW 메커니즘은 10GB 파일 전체를 쓰기 가능 레이어로 복사하는 작업을 수행해야 하여 매우 비효율적이다.
이러한 이유로, DB의 데이터 파일처럼 크고, 쓰기 작업이 빈번한 파일들은 CoW의 영향을 받지 않는 '도커 볼륨 (Docker Volume)'에 저장하여 관리하는 것이 필수적이다.
SQL Server 컨테이너를 실행 데모를 위한 깨끗한 환경을 위해 기존 컨테이너와 볼륨을 삭제하는 과정을 거친 후,
docker run --env "ACCEPT_EULA=Y" --env "SA_PASSWORD=<YourStrong!Passw0rd>" --memory 2048m -p 1433:1433 --name sql2022-latest --hostname sql2022-latest --restart unless-stopped -d --mount source=sqlvolume,target=/var/opt/mssql mcr.microsoft.com/mssql/server:2022-latest
해당 명령어를 이용하여 SQL Server 2022 컨테이너를 실행한다.
컨테이너 실행 후에는 Windows Defender 방화벽에서 액세스를 허용할지 묻는 창이 나타나며, '액세스 허용'을 선택해야 한다.
-e (환경 변수):
ACCEP_EULA=Y
(라이선스 동의) 와 SA_PASSWORD
(관리자 비밀번호 설정)은 최소한의 필수 조건MSSQL_PID
로 에디션 지정 가능--env-file
옵션으로 환경 변수들을 파일로 관리 가능-p (포트 매핑):
-p 1433:1433
-> 호스트 PC의 1433번 포트와 Container의 1433번 포트를 매핑-p 1401:1433
or -p 1402:1433
)--name 및 --hostname:
--restart unless-stopped:
-d (Detached):
--mount (볼륨 연결):
docker exec -it <컨테이너이름> bash
: 실행 중인 컨테이너 내부에 접속하여 상호작용이 가능한(interactive terminal, -it) bash 셸을 사용함.
내부에서 ps -ef
명령을 실행하면, SQL Server와 관련된 최소한의 프로세스만 실행되는 것을 통해 컨테이너의 완벽한 격리성을 확인할 수 있음.
ls /var/opt/mssql
명령으로 데이터, 로그, 인증서 폴더 등 SQL Server의 실제 파일 구조를 탐색할 수 있음.
Container는 기본적으로 Host의 모든 리소스를 사용하려고 시도한다.
docker update 명령어를 사용하게 되면, 이미 실행중인 Container의 리소스 제한을 동적으로 변경할 수 있다.
docker stats
: 현재 컨테이너의 CPU, 메모리 등 리소스 사용량을 실시간으로 모니터링함.
docker update --cpus=2 --memory=1g <컨테이너이름>
: 해당 컨테이너를 CPU 코어를 최대 2개까지, 메모리를 최대 1GB까지만 사용하도록 즉시 제한함. (docker stats로 확인하면 제한 적용 확인 가능)
두 개의 SQL Server 컨테이너는 동일한 볼륨을 공유할 수 없다.
만약 시도할 경우, 두 번째 컨테이너는 이미 사용 중인 데이터베이스 파일에 접근하려다 잠금 문제로 인해 오류(17113)를 발생시키며 시작되지 않는다.
각 SQL Server 인스턴스는 고유한 데이터베이스 파일 세트와 볼륨을 가져야한다.
백업 파일 복사:
docker cp <로컬경로/파일.bak> <컨테이너이름>:<컨테이너경로>
명령어로 로컬 PC의 백업 파일을 컨테이너 내부로 복사
파일 소유권 변경 :
SQL Server 2019 이상 버전의 컨테이너는 보안 강화를 위해 시스템 최고 권한 root가 아닌, 권한이 제한된 mssql 사용자로 실행된다.
로컬에서 복사된 파일은 기본적으로 root 소유이므로, mssql 사용자가 이 파일을 읽을 수 없으므로, docker exec <컨테이너이름> chown mssql:mssql <파일경로>
명령어를 사용하여 파일 소유권을 반드시 변경해야 한다.
데이터베이스 복원:
SSMS (SQL Server Management Studio)를 사용해 localhost로 컨테이너에 접속한 뒤, 권한 문제가 해결된 백업 파일을 이용해 GUI로 데이터베이스를 복원한다.
복원 후 ALTER DATABASE ... SET COMPATIBILITY_LEVEL = 160
과 같은 명령으로 호환성 수준을 최신으로 맞출 수 있다.
파일 복사 (컨테이너 → 로컬):
docker cp <컨테이너이름>:<컨테이너경로/파일> <로컬경로>
명령어를 사용하여 컨테이너 내부의 에러 로그 파일 등을 로컬 PC로 가져올 수 있다.
SQL Server 내부 로그 : 전통적인 DBA 방식대로 SSMS에서 sp_readerrorlog
를 실행하여 로그를 확인할 수 있음.
Docker 로그 : docker logs <컨테이너이름>
명령어가 훨씬 편리하고 강력하다.
특히 -f 옵션을 추가하면 로그를 실시간으로 스트리밍할 수 있어, 로그인 실패나 비밀번호 복잡성 정책 위반으로 인해 컨테이너가 시작되지 않는 등의 문제를 즉시 파악하고 해결하는 데 매우 유용함.
Docker는 기본적으로 bridge 라는 가상 네트워크를 사용한다.
하나의 Host에서 여러 개의 SQL Server Container를 실행하려면, docker run 시 -p 옵션의 Host Port를 다르게 지정해야 한다.
-p 1433:1433
-p 1401:1433
또한, docker network inspect bridge
명령을 실행하면, bridge 네트워크의 게이트웨이 IP와, 여기에 연결된 각 컨테이너에 할당된 내부 IP 주소 등 상세한 네트워크 구성을 확인할 수 있다.
Container의 가장 강력한 장점 중 하나로, 데이터 손실이나 긴 Downtime 없이 버전을 업그레이드 하는 방법이다.
예시
구버전 (예: mcr.microsoft.com/mssql/server:2022-CU8-ubuntu-20.04) 컨테이너를 영속성 볼륨 (sqlvolume)과 함께 실행하고, SSMS로 접속하여 테스트 데이터베이스 (testDB)를 생성
해당 컨테이너를 중지하고 삭제. 컨테이너는 사라졌지만, testDB의 데이터 파일은 sqlvolume에 존재함.
최신 버전 (latest)의 SQL Server 이미지를 사용하여 '동일한 볼륨(sqlvolume)'에 연결하여 새 컨테이너를 실행
결과적으로, SQL Server가 시작되면서 볼륨에 저장된 구버전 데이터 파일들을 감지하고, 자동으로 최신 버전으로 업그레이드를 진행.
이 시간 동안 잠시 접속이 안 될 수 있으며, 에러 로그에는 'master' is upgrading...과 같은 메시지가 기록됨. 잠시 후 SELECT @@VERSION
으로 버전을 확인하면 최신 버전으로 올라간 것을 볼 수 있고, testDB 역시 그대로 존재하며 정상적으로 접근 가능함.
이러한 방식은 데이터의 영속성을 보장하면서도 애플리케이션만 손쉽게 교체할 수 있는 컨테이너의 핵심 철학을 명확히 보여준다.
덕분에 DBA는 복잡한 마이그레이션 절차 없이, 단 몇 개의 명령만으로 다운타임을 최소화하며 안전하게 시스템을 최신 상태로 유지할 수 있다.
강연자는 자신의 경험을 바탕으로 고가용성이 필요한 프로덕션 환경의 SQL Server 구성에는 쿠버네티스보다 '윈도우 서버 장애 조치 클러스터 (Windows Server Failover Cluster, WSFC)'가 더 실용적이고 안정적인 선택이라고 주장한다.
DBA입장에서 쿠버네티스의 단점에 비해, WSFC는 수십 년간 SQL Server를 위해 검증된 기술이며, 설치가 매우 쉽고 비용 효율적이다.
따라서, Docker는 개발, 테스트, CI/CD 파이프라인에서 격리된 환경을 신속하게 구축하고 복제하는 데 매우 유용하므로 적극적으로 사용해야 한다고 한다.
다만, 프로덕션 환경의 고가용성이 필요할 때는 WSFC를 우선적으로 고려하는 것이 좋다고 한다.
추가적으로, Docker의 대안으로 Podman이 최근에 큰 주목을 받고 있으며, 백그라운드에서 항상 실행되는 데몬 (에이전트) 없이 작동하기 때문에 Docker보다 더 안전한 아키텍처로 주목받고 있음을 강조한다.
결론: 해당 프레젠테이션은 DBA가 자신의 업무 환경에 맞게 컨테이너 기술을 어떻게 사용해야 하는지에 대한 실용적인 가이드이다.