JSON 대체자 Pkl 소개

dante Yoon·2024년 2월 11일
1

dante-tech

목록 보기
1/1
post-thumbnail

유튜브 영상으로 보기: https://www.youtube.com/watch?v=yUPRXVCb5Zo

Pkl 피클이란

피클은 24년 2월 1일 애플에서 공개한 설정파일을 작성할 수 있는 언어입니다. 여기서 설정파일은 github action, 라이브러리 패키지 및 의존성 정의 (package.json), 쿠버네티스 객체 정의등 특정 객체를 생성하거나 서버가 특정 동작을 할 때 필요한 설정 값을 정의하는 역할을 합니다.

설정 파일을 작성하는 형식은 아래와 같이 매우 다양합니다.

yaml

name: Swallow
job:
  title: Sr. Nest Maker
  company: Nests R Us
  yearsOfExperience: 2

json

{
  "name": "Swallow",
  "job": {
    "title": "Sr. Nest Maker",
    "company": "Nests R Us",
    "yearsOfExperience": 2
  }
}

xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>name</key>
  <string>Swallow</string>
  <key>job</key>
  <dict>
    <key>title</key>
    <string>Sr. Nest Maker</string>
    <key>company</key>
    <string>Nests R Us</string>
    <key>yearsOfExperience</key>
    <integer>2</integer>
  </dict>
</dict>
</plist>

properties

name = Swallow
job.title = Sr. Nest Maker
job.company = Nests R Us
job.yearsOfExperience = 2

피클은 각 설정파일의 형식을 하나로 통일하여 작성하게 해주고 이를 필요한 형식으로 변환해주며 작성하는 단계에서 정적 체크를 통해 유효성 검사를 제공해주는 역할을 합니다.

앞서 작성했었던 각 포멧은 아래 피클 파일의 결과물입니다.

name = "Swallow"

job {
  title = "Sr. Nest Maker"
  company = "Nests R Us"
  yearsOfExperience = 2
}
↓

yaml 파일을 작성할 때 제대로 indentationd이 되어있지 않거나 : 를 빼먹거나 리스트 형식을 잘못 작성하더라도 유효성 검사가 이뤄지지 않기 때문에 실행해보기 전까지는 어떤 부분이 잘못 작성되었는지 발견하기가 어렵습니다.

예시: 쿠버네티스 오브젝트

쿠버네티스 오브젝트 스펙을 yaml에 정의할때 파일 하나에만 모든 쿠버네티스 오브젝트의 내용을 명시하지 않습니다. service, load balancer, pod등 각 객체 타입마다 별도의 파일을 정의해야 합니다. 이는 배포 형상을 파악하기 위해 여러 yaml 파일을 살펴보며 각 쿠버네티스 객체의 관계를 파악해야 하고 수정이 필요할 떄마다 여러 파일을 열어봐야 한다는 문제점을 가지고 있으며 yaml 파일은 유효성 검사를 해주지 않기 때문에 도커라이즈된 컨테이너를 실제로 배포해보기 전까지 내가 작성한 설정파일에 잘못 명시한 부분이 있는지 파악하기 어렵다는 문제점을 같이 가지고 있습니다. 그리고 yaml에서는 조건문을 사용하지 못한다는 제한사항도 있습니다.

hard to find kubernetes objects

피클의 공식문서의소개를 보면 Programmable 이란 수식어로 피클의 특징을 설명합니다. 그렇습니다. 프로그래밍이 가능합니다.

amends "template.pkl"

deployments {
  default {
    spec {
      selector {
        matchLabels {
          ["app"] = module.app
          ["env"] = module.env
        }
      }
      template {
        metadata {
          labels {
            ["app"] = module.app
            ["env"] = module.env
          }
        }
        spec {
          containers {
            default {
              resources {
                requests {
                  when (module.env == "production") {
                    ["cpu"] = 1
                    ["memory"] = 1.gib
                  }
                  when (module.env == "staging") {
                    ["cpu"] = 0.1
                    ["memory"] = 100.mib
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

위 코드는 pkl 파일 확장자로 쓰여진 k8s deployments 타입 객체 설정 파일인데요, when 이라고 하는 조건문이 사용되는걸 볼 수가 있습니다.

원본 코드: https://github.com/apple/pkl-k8s-examples/blob/main/pkl/advanced/deployments.pkl

주요 특징들

조건문

아래 파일에서 이메일은 String 타입이고 포트넘버는 1000 보다 높은 숫자여야 한다고 정의한 후 컴파일을 하면 유효성 검사에서 걸리는 걸 알 수 있습니다.
validation check

builtin validation

https://pkl-lang.org/blog/introducing-pkl.html#built-in-validation

모듈 / 랭귀지 바인딩

다음 Application.pkl 예제 파일을 만들었습니다. 이 파일은 공식문서에서 찾아볼 수 있습니다.

module Application

/// The hostname that this server responds to.
hostname: String

/// The port to listen on.
port: UInt16

/// The environment to deploy to.
environment: Environment

/// The database connection for this application
database: Database


```pkl
class Database {
  /// The username for this database.
  username: String

  /// The password for this database.
  password: String

  /// The remote host for this database.
  host: String

  /// The remote port for this database.
  port: UInt16

  /// The name of the database.
  dbName: String
}

typealias Environment = "dev"|"qa"|"prod"

ammends 키워드를 사용해 다른 피클 파일에서 위 설정을 사용할 수 있습니다.

localhost.pkl

amends "Application.pkl"

hostname = "localhost"

port = 3599

environment = "dev"

database {
  host = "localhost"
  port = 5786
  username = "admin"
  password = read("env:DATABASE_PASSWORD") 
  dbName = "myapp"
}

패키지 파일로 모듈을 만들어 url을 통해 다른 플랫폼에서 쉽게 사용할 수 있습니다. 여기서 플랫폼은 Go, Kotlin등 다른 언어 플랫폼, 혹은 다른 프로젝트를 의미합니다.

미리 작성해둔 Pkl 스키마를 각기 다른 언어 플랫폼에서 가져다가 class/structs 구조체 내부에서 참조할 수 있습니다.

예를 들어서 위에서 작성했던 Application.pkl 파일이 각 언어 플랫폼에서 어떻게 사용되는지 살펴보세요.

https://pkl-lang.org/blog/introducing-pkl.html#built-in-validation

for 루프

scss 에서 loop를 돌듯이 다음 sidecars.pkl 파일에서 루프를 돌며 다양한 타입의 리소스 객체들을 정의할 수 있습니다.

sidecars.pkl

import "Application.pkl"

hidden db: Application.Database = new {
  host = "localhost"
  username = "admin"
  password = read("env:DATABASE_PASSWORD")
  dbName = "myapp"
}

sidecars {
  for (offset in List(0, 1, 2, 3)) {
    (db) {
      port = 6000 + offset
    }
  }
}



리스크립트 보는 느낌인데 국내에서 많이 사용되기까지는 시간이 오래 걸릴 것 같다고 추측합니다.

공통 설정 언어 -> json, yaml, xml -> 리소스 생성 및 실행

특정 리소스 실행까지 한 스텝을 넓히는건데 이 기술의 필요성을 느낄 회사보다 귀찮음을 느낄 회사도 많을 것 같고, 데브옵스에서 발표용도나 사내 레거시 청산할 때 Tech OKR로 잡고 할 수는 있을 것 같네요.

profile
성장을 향한 작은 몸부림의 흔적들

0개의 댓글