Ktor에서 Docker를 이용하여 PostgreSQL 연동하는 과정에 대한 글입니다!
프로젝트 생성 방법은 이 글을 참고해주세요!
준비물 : Docker Desktop, Ktor 프로젝트
먼저, PostgreSQL Docker 이미지를 풀받고 컨테이너를 실행합니다. 기본적으로 Docker Hub에 있는 postgres
이미지를 사용하겠습니다.
터미널에서 아래 명령어를 실행하여 PostgreSQL Docker 컨테이너를 시작합니다.
docker pull postgres:latest
이제 PostgreSQL 컨테이너를 실행합니다. 아래 명령어로 컨테이너를 실행하면서 데이터베이스 이름, 사용자, 비밀번호를 설정합니다.
docker run --name my_postgres -e POSTGRES_USER=myuser -e POSTGRES_PASSWORD=mypassword -e POSTGRES_DB=mydatabase -p 5432:5432 -d postgres
my_postgres
: 컨테이너 이름POSTGRES_USER
: 데이터베이스 사용자 이름 (myuser
).POSTGRES_PASSWORD
: 데이터베이스 비밀번호 (mypassword
).POSTGRES_DB
: 생성할 기본 데이터베이스 이름 (mydatabase
).p 5432:5432
: 호스트와 컨테이너 간의 포트 매핑 (호스트의 5432 포트를 컨테이너의 5432 포트와 연결).d
: 백그라운드에서 컨테이너를 실행.이 명령어를 실행하면 PostgreSQL이 백그라운드에서 실행되고, 5432
포트에서 연결을 대기하게 됩니다.
저는 아래와 같이 입력하였습니다!
docker run --name ktor-db -e POSTGRES_USER=mic050r -e POSTGRES_PASSWORD=123456 -e POSTGRES_DB=test -p 5432:5432 -d postgres
다음 명령어로 컨테이너가 제대로 실행 중인지 확인할 수 있습니다.
docker ps
컨테이너가 정상적으로 실행 중이라면, 5432
포트에서 PostgreSQL이 실행되고 있는 것을 확인할 수 있습니다.
PostgreSQL이 Docker에서 실행 중이라면, 이제 Ktor 프로젝트에서 이 데이터베이스에 연결하는 방법을 설정해야 합니다.
Application.kt
또는 환경 변수 파일에서 PostgreSQL에 연결하기 위한 JDBC URL을 설정합니다. PostgreSQL Docker 컨테이너가 로컬에서 실행 중이므로, localhost
와 5432
포트를 사용합니다.
val hikariConfig = HikariConfig().apply {
jdbcUrl = "jdbc:postgresql://localhost:5432/mydatabase"
driverClassName = "org.postgresql.Driver"
username = "myuser"
password = "mypassword"
maximumPoolSize = 10
}
val dataSource = HikariDataSource(hikariConfig)
Database.connect(dataSource)
jdbcUrl
: "jdbc:postgresql://localhost:5432/mydatabase"
로 설정.localhost
는 Docker 컨테이너가 호스트의 네트워크에서 접근 가능하기 때문에 사용username
: myuser
(컨테이너 실행 시 설정한 사용자 이름)password
: mypassword
(컨테이너 실행 시 설정한 비밀번호)Ktor 프로젝트에서 PostgreSQL과 HikariCP를 사용할 수 있도록 build.gradle.kts
파일에 의존성을 추가해야 합니다.
dependencies {
// PostgreSQL JDBC 드라이버
implementation("org.postgresql:postgresql:42.6.0")
// Exposed ORM 라이브러리
implementation("org.jetbrains.exposed:exposed-core:0.41.1")
implementation("org.jetbrains.exposed:exposed-dao:0.41.1")
implementation("org.jetbrains.exposed:exposed-jdbc:0.41.1")
// HikariCP (커넥션 풀)
implementation("com.zaxxer:HikariCP:5.0.1")
}
package example.com
import example.com.plugins.*
import io.ktor.server.application.*
import io.ktor.server.netty.*
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.jetbrains.exposed.sql.Database
fun main(args: Array<String>) {
EngineMain.main(args)
}
fun Application.module() {
// 데이터베이스 설정을 여기서 초기화
configureDatabase()
// 다른 설정들
configureSerialization()
configureHTTP()
configureSecurity()
configureRouting()
}
fun Application.configureDatabase() {
val hikariConfig = HikariConfig().apply {
jdbcUrl = "jdbc:postgresql://localhost:5432/test"
driverClassName = "org.postgresql.Driver"
username = "mic050r"
password = "123456"
maximumPoolSize = 10
}
try {
val dataSource = HikariDataSource(hikariConfig)
Database.connect(dataSource)
// 연결 성공 시 로그 출력
environment.log.info("Database connected successfully!")
} catch (e: Exception) {
// 연결 실패 시 오류 로그 출력
environment.log.error("Database connection failed: ${e.message}")
}
}
로그를 보니 잘 실행되는 것을 확인했습니다!
src/main/kotlin/example/com/Application.kt
package example.com
import example.com.plugins.*
import io.ktor.server.application.*
import io.ktor.server.netty.*
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.jetbrains.exposed.sql.Database
fun main(args: Array<String>) {
EngineMain.main(args)
}
fun Application.module() {
// 데이터베이스 설정을 여기서 초기화
configureDatabase()
// 다른 설정들
configureSerialization()
configureHTTP()
configureSecurity()
configureRouting()
}
fun Application.configureDatabase() {
val hikariConfig = HikariConfig().apply {
jdbcUrl = "jdbc:postgresql://localhost:5432/test"
driverClassName = "org.postgresql.Driver"
username = "mic050r"
password = "123456"
maximumPoolSize = 10
}
try {
val dataSource = HikariDataSource(hikariConfig)
Database.connect(dataSource)
// 연결 성공 시 로그 출력
environment.log.info("Database connected successfully!")
} catch (e: Exception) {
// 연결 실패 시 오류 로그 출력
environment.log.error("Database connection failed: ${e.message}")
}
}
build.gradle.kts
val kotlin_version: String by project
val logback_version: String by project
val exposed_version: String by project
val h2_version: String by project
plugins {
kotlin("jvm") version "2.0.10"
id("io.ktor.plugin") version "2.3.12"
id("org.jetbrains.kotlin.plugin.serialization") version "2.0.10"
}
group = "example.com"
version = "0.0.1"
application {
mainClass.set("io.ktor.server.netty.EngineMain")
val isDevelopment: Boolean = project.ext.has("development")
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.jetbrains.exposed:exposed-core:0.41.1")
implementation("org.jetbrains.exposed:exposed-dao:0.41.1")
implementation("org.jetbrains.exposed:exposed-jdbc:0.41.1")
implementation("io.ktor:ktor-server-core-jvm")
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm")
implementation("io.ktor:ktor-server-content-negotiation-jvm")
// Exposed ORM 라이브러리
implementation("org.jetbrains.exposed:exposed-core:$exposed_version")
implementation("org.jetbrains.exposed:exposed-jdbc:$exposed_version")
// PostgreSQL JDBC 드라이버
implementation("org.postgresql:postgresql:42.6.0")
// HikariCP (커넥션 풀)
implementation("com.zaxxer:HikariCP:5.0.1")
implementation("com.h2database:h2:$h2_version")
implementation("io.ktor:ktor-server-openapi")
implementation("io.ktor:ktor-server-auth-jvm")
implementation("io.ktor:ktor-server-netty-jvm")
implementation("ch.qos.logback:logback-classic:$logback_version")
implementation("io.ktor:ktor-server-config-yaml")
testImplementation("io.ktor:ktor-server-test-host-jvm")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
}