1. Atlas 소개

atlas

Atlas는 현대적인 DevOps 원칙을 사용하여 데이터베이스 스키마를 관리하고 이주하는 데 특별히 설계된 언어 독립적인 도구입니다. 두 가지 워크플로 옵션을 제공합니다:

  • 선언적: Terraform과 유사하게, Atlas는 데이터베이스의 현재 상태를 HCL, SQL 또는 ORM 스키마를 사용하여 정의된 원하는 상태와 비교합니다. 이 비교를 기반으로 데이터베이스를 원하는 상태로 전환하기 위한 이주 계획을 생성하고 실행합니다.
  • 버전 관리: 다른 도구와 달리, Atlas는 자동으로 스키마 이주를 계획합니다. 사용자는 원하는 데이터베이스 스키마를 HCL, SQL 또는 선택한 ORM을 사용하여 설명하고, Atlas를 사용하여 데이터베이스에 필요한 이주를 계획하고 검토하고 적용할 수 있습니다.

Atlas의 주요 장점은 데이터베이스 관리의 복잡성을 간소화하여 버전 관리, 협업 및 구현을 쉽게 하는 것입니다.

2. Atlas 설치

데이터베이스 버전을 관리하기 전에 Atlas를 설치해야 합니다. 다음은 각 플랫폼용 설치 단계입니다.

2.1 macOS + Linux 설치

macOS 또는 Linux 시스템에서 다음 커맨드 라인을 사용하여 최신 버전의 Atlas를 다운로드하고 설치할 수 있습니다:

curl -sSf https://atlasgo.sh | sh

이 커맨드는 자동으로 운영 체제 버전을 감지하고 적합한 빌드 버전을 다운로드하여 Atlas 이진 파일을 실행 가능한 경로에 배치합니다.

2.2 Homebrew를 통한 설치

macOS를 사용하고 이미 Homebrew 패키지 매니저를 설치한 경우, 다음 명령어를 실행하면 Atlas를 간단히 설치할 수 있습니다:

brew install ariga/tap/atlas

이 명령어는 Homebrew 저장소에서 최신 버전의 Atlas를 가져와 설치합니다.

2.3 Docker 설치

Docker를 통해 Atlas를 설치하고 실행하는 것은 특히 임시 테스트나 호스트 시스템에 추가 소프트웨어를 설치하지 않으려는 사용자들에게 빠르고 편리한 방법입니다.

먼저 Atlas Docker 이미지를 가져옵니다:

docker pull arigaio/atlas

그런 다음 성공적인 설치를 확인하기 위해 도움말 명령을 실행할 수 있습니다:

docker run --rm arigaio/atlas --help

컨테이너가 호스트 네트워크 또는 로컬 디렉터리에 액세스해야 하는 경우, --net=host 플래그를 사용하고 필요한 디렉토리를 마운트할 수 있습니다:

docker run --rm --net=host \
  -v $(pwd)/migrations:/migrations \
  arigaio/atlas migrate apply \
  --url "mysql://root:pass@:3306/test"

2.4 Windows 설치

https://release.ariga.io/atlas/atlas-windows-amd64-latest.exe에서 이진 파일을 다운로드하고 설치 경로를 시스템의 PATH 환경 변수에 추가하세요.

3. Atlas를 사용하여 기존 데이터베이스 테이블 구조 내보내기

Atlas는 기존 데이터베이스의 구조를 내보내는 데 사용할 수 있는 atlas schema inspect 명령을 제공합니다. 이 명령은 데이터베이스 URL에서 데이터베이스 설명을 읽어 기본적으로 Atlas HCL 형식, SQL 형식 및 JSON 형식의 세 가지 다른 형식으로 출력합니다. 이 안내서에서는 Atlas HCL 및 SQL 형식을 사용하는 방법을 보여드리겠습니다. JSON 형식은 일반적으로 jq를 사용하여 출력을 처리하는 데 사용됩니다.

로컬에서 실행 중인 MySQL 인스턴스를 검사하고 출력을 schema.hcl이라는 파일에 작성하려면 다음 명령을 사용하십시오:

atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > schema.hcl

schema.hcl 파일을 열어보면 데이터베이스를 설명하는 Atlas 테이블 구조 정의가 들어 있습니다(HCL은 Atlas에서 정의한 데이터베이스에 독립적인 테이블 구조 설정 형식입니다). 예를 들어, 이 파일에는 다음 내용이 포함됩니다:

table "users" {
  schema = schema.example
  column "id" {
    null = false
    type = int
  }
  column "name" {
    null = true
    type = varchar(100)
  }
  primary_key {
    columns = [column.id]
  }
}

이 코드 블록은 idname 열이 있는 테이블 구조를 나타냅니다. schema 필드는 이 문서의 다른 곳에 정의된 example 모델 정의를 참조합니다. 또한 primary_key 하위 블록은 테이블의 주 키로 id 열을 지정합니다. Atlas는 작동 중인 데이터베이스의 구문 구조를 모사하려 노력합니다. 이 예에서 id 열의 유형은 int이며, name 열의 유형은 varchar(100)입니다.

마찬가지로 데이터베이스의 SQL 모델 정의를 내보내려면 다음 명령을 사용할 수 있습니다:

atlas schema inspect -u "mysql://root:pass@localhost:3306/example" --format '{{ sql . }}' > schema.sql

schema.sql 파일을 열어보면 일반적으로 CREATE TABLE 문을 포함하는 데이터베이스의 SQL 설명이 들어 있습니다.

이 접근 방식을 통해 기존 데이터베이스 테이블 구조의 세부 정보를 쉽게 이해하고 후속 버전 이관을 위한 정확한 참조가 제공됩니다.

4.1 선언적 워크플로우

Atlas의 선언적 워크플로우는 사용자가 데이터베이스의 원하는 최종 상태를 선언적으로 정의할 수 있도록 합니다. 사용자는 데이터베이스 스키마의 최종 상태가 어떨지만 설명하면, Atlas 도구가 자동으로 마이그레이션 계획을 생성하고 실행하여 데이터베이스 스키마를 현재 상태에서 예상 상태로 안전하게 전환합니다.

다음은 선언적 워크플로우를 사용하여 원하는 데이터베이스 상태를 정의하고 달성하는 방법입니다:

4.1.1 대상 테이블 구조 정의

먼저, HCL, SQL 또는 ORM(Object-Relational Mapping) 형식일 수 있는 예상 데이터베이스 구조를 정의하는 파일을 만들어야 합니다.

예를 들어 HCL 형식을 가져오면 새로운 blog_posts 테이블을 정의합니다:

table "blog_posts" {
  schema = schema.example
  column "id" {
    null = false
    type = int
  }
  column "title" {
    null = true
    type = varchar(100)
  }
  column "body" {
    null = true
    type = text
  }
  column "author_id" {
    null = true
    type = int
  }
  primary_key {
    columns = [column.id]
  }
  foreign_key "author_fk" {
    columns     = [column.author_id]
    ref_columns = [table.users.column.id]
  }
}

팁: HCL의 구문 형식은 이후 섹션에서 다룰 예정입니다.

4.1.2 Atlas 도구를 사용한 마이그레이션 실행

데이터베이스 테이블 구조 정의가 완료되면 Atlas 도구의 schema apply 명령을 사용하여 마이그레이션을 실행할 수 있습니다.

atlas schema apply \
  -u "mysql://root:pass@localhost:3306/example" \
  --to file://schema.hcl

위 명령을 실행한 후에 Atlas는 기존 데이터베이스 스키마를 파일에 정의된 스키마와 비교하여 마이그레이션 계획을 생성하고 사용자에게 실행 확인을 요청합니다. 사용자가 실행 계획을 확인하면 Atlas는 데이터베이스에서 마이그레이션을 수행하고 원하는 상태로 업데이트합니다.

4.2 버전 워크플로우

버전 워크플로우는 Atlas에서 지원하는 다른 사용 모드로, 때로는 "변경 기반 마이그레이션"이라고도 합니다. 데이터베이스 스키마 변경 사항을 코드 리뷰 프로세스에서 버전 관리하고 검토해야 하는 시나리오에 적합합니다.

버전 워크플로우의 단계는 다음과 같습니다:

4.2.1 차이점 계산

마이그레이션을 시작하기 전에 현재 데이터베이스 구조를 원하는 상태와 비교하고 두 가지 간의 차이를 결정하는 것이 필요합니다. 이는 atlas migrate diff 명령을 실행하여 수행할 수 있습니다.

atlas migrate diff create_blog_posts \
  --dir "file://migrations" \
  --to "file://schema.hcl" \
  --dev-url "docker://mysql/8/example"

--dir는 마이그레이션 폴더의 URL을 지정하며, 기본값은 file://migrations입니다. --to는 원하는 상태의 URL을 지정하고, --dev-url은 차이를 계산하는 데 사용되는 개발 데이터베이스의 URL을 제공합니다 (주의: 이 --dev-url은 Atlas가 차이를 계산하는 데 사용하는 빈 데이터베이스를 지정해야 합니다).

팁: SQL 파일을 생성하려면 --format 매개변수를 사용하여 형식을 설정하는 방법에 대해 이전 섹션을 참조하십시오.

4.2.2 마이그레이션 변경 적용

차이점 계산이 완료되면 Atlas는 migrations 폴더에 저장된 두 개의 마이그레이션 파일을 생성합니다. 예를 들어, 선택한 형식이 SQL인 경우 diff 명령에 의해 생성된 다음과 같은 SQL 파일에는 새 테이블을 생성하는 마이그레이션 명령이 포함됩니다.

-- "blog_posts" 테이블 생성
CREATE TABLE `blog_posts` (
  `id` int NOT NULL,
  `title` varchar(100) DEFAULT NULL,
  `body` text DEFAULT NULL,
  `author_id` int NULL REFERENCES `users`(id),
  PRIMARY KEY (`id`)
);

마이그레이션 파일이 생성되면 버전 관리 도구 (예: Git)를 사용하여 이러한 변경 사항을 관리할 수 있습니다. 이 접근 방식을 사용하면 개발 환경에서 여러 데이터베이스 테이블 구조 수정을 수행하고 출시 시에는 Atlas 명령을 사용하여 개발 환경과 UAT 환경을 비교하여 데이터베이스 테이블 구조 마이그레이션 파일을 생성할 수 있습니다. 이러한 마이그레이션 파일은 UAT 및 프로덕션 환경에 적용하여 데이터베이스를 업그레이드할 수 있습니다.

선언적 및 버전 관리 두 개의 워크플로우는 데이터베이스 스키마 변경을 관리하는 프로젝트의 필요에 가장 적합한 방법을 선택하여 다양한 개발 및 배포 모드에 대해 유연성을 제공합니다.

5. HCL 포맷 설명

5.1 소개

HCL은 데이터베이스 테이블 구조 정의를 설명하는 데 사용되는 선언적 언어입니다. Atlas는 HCL 형식을 사용하여 데이터베이스 스키마를 작성하며, 변수 주입 및 추가 어노테이션과 같은 기능을 지원하여 가독성이 높고 유지보수가 쉬우며 다양한 측면을 설명하는 풍부한 구조를 제공합니다.

팁: 프로젝트가 여러 데이터베이스에 적응해야 하는 경우, HCL을 사용하여 데이터베이스 별로 테이블 구조를 설명하는 것이 매우 편리할 수 있습니다.

5.2 schema 오브젝트

schema 오브젝트는 데이터베이스 스키마를 설명하는 데 사용됩니다. MySQL 및 SQLite에서는 DATABASE를, PostgreSQL에서는 SCHEMA를 대표합니다. HCL 파일은 하나 이상의 schema 오브젝트를 포함할 수 있습니다.

schema "public" {
  comment = "스키마 코멘트"
}

schema "private" {}

5.3 table 오브젝트

table 오브젝트는 SQL 데이터베이스의 테이블을 설명하는 데 사용됩니다. 이는 열, 인덱스, 제약 조건 및 다양한 다른 데이터베이스 드라이버가 지원하는 속성을 포함합니다.

table "users" {
  schema = schema.public
  column "id" {
    type = int
  }
  column "name" {
    type = varchar(255)
  }
  column "manager_id" {
    type = int
  }
  primary_key {
    columns = [
      column.id
    ]
  }
  index "idx_name" {
    columns = [
      column.name
    ]
    unique = true
  }
  foreign_key "manager_fk" {
    columns     = [column.manager_id]
    ref_columns = [table.users.column.id]
    on_delete   = CASCADE
    on_update   = NO_ACTION
  }
}

5.5 primary_key 객체

primary_key는 테이블의 기본 키를 정의하는 table의 하위 리소스입니다.

primary_key {
  columns = [column.id]
}

5.6 foreign_key 객체

foreign_key는 다른 테이블의 열을 참조하는 열을 정의하는 table의 하위 리소스입니다.

table "orders" {
  schema = schema.market
  // ...
  column "owner_id" {
    type = integer
  }
  foreign_key "owner_id" {
    columns     = [column.owner_id]
    ref_columns = [table.users.column.id]
    on_update   = NO_ACTION
    on_delete   = NO_ACTION
  }
}

5.7 index 객체

index 객체는 테이블의 인덱스를 나타냅니다.

index "idx_name" {
  columns = [
    column.name
  ]
  unique = true
}