CSI 볼륨 사용

CSI 볼륨 사용 (Use CSI volumes)

Nomad의 Container Storage Interface (CSI) 통합은 클러스터 안에서 실행되는 상태 저장 워크로드의 외부 스토리지 볼륨을 관리할 수 있어요. CSI 공급자는 Nomad 작업으로 실행되는 서드파티 플러그인이며, 클라우드 공급자가 만든 볼륨을 마운트할 수 있어요. Nomad는 스케줄링 과정에서 CSI가 관리하는 볼륨을 인지하므로, 특정 클라이언트에서 볼륨을 사용할 수 있는지에 따라 워크로드를 스케줄링할 수 있어요.

출처: 문서

본문

각 스토리지 공급자는 자체 CSI 플러그인을 만들며, Nomad에서 그 모두를 활용할 수 있어요. AWS Elastic Block Storage (EBS)나 Elastic File System (EFS) 볼륨, GCP persistent disks, Digital Ocean droplet 스토리지 볼륨, 또는 Portworx 같은 벤더 무관한 서드파티 공급자로부터 스토리지 볼륨을 요청하는 작업을 시작할 수 있어요. 이는 또한 스토리지 공급자가 Kubernetes를 지원하기 위해 작성한 많은 플러그인이 Nomad도 지원한다는 것을 의미해요. 플러그인 목록은 Kubernetes CSI 개발자 문서에서 찾을 수 있어요.

Nomad의 host_volume 기능과 달리, CSI가 관리하는 볼륨은 Nomad 클라이언트 구성을 변경하지 않고도 Nomad 클러스터에 추가하고 제거할 수 있어요.

Nomad의 CSI 통합을 사용하는 것은 세 가지 핵심 워크플로로 구성돼요: CSI 플러그인 실행, 해당 플러그인에 볼륨 등록, 해당 볼륨을 요청하는 작업 실행. 이 가이드에서는 AWS Elastic Block Storage (EBS) 플러그인을 실행하고, 해당 플러그인에 EBS 볼륨을 등록하며, 영구 저장을 위해 그 볼륨을 요청하는 MySQL 워크로드를 배포할 거예요.

사전 요구 사항 (Prerequisites)

이 가이드에서 설명하는 작업을 수행하려면 다음이 필요해요:

  • Consul이 설치된 AWS의 Nomad 환경. 이 Terraform 환경을 사용해 샌드박스 환경을 구성할 수 있어요. 이 튜토리얼은 서버 노드 1개와 클라이언트 노드 2개로 구성된 클러스터를 가정해요.
  • Nomad v1.3.0 이상

참고

이 튜토리얼은 데모용이며 단일 서버 노드만 가정해요. 프로덕션 구성은 레퍼런스 아키텍처를 참조해요.

MySQL 클라이언트 설치 (Install the MySQL client)

MySQL 클라이언트를 사용해 MySQL 데이터베이스에 연결하고 데이터를 확인할 거예요. Nomad 클라이언트의 포트 3306에 접근할 수 있는 노드에 설치되어 있는지 확인해요:

Ubuntu:

CentOS:

macOS via Homebrew:

AWS EBS 볼륨 배포 (Deploy an AWS EBS volume)

다음으로, Nomad 클러스터를 만드는 데 사용한 것과 같은 Terraform 스택을 사용해 CSI 플러그인이 작업에 필요한 곳에 마운트할 AWS EBS 볼륨을 만들어요.

Terraform 스택에 다음 새 리소스를 추가해요.

  name   = "mount-ebs-volumes"
  role   = aws_iam_role.instance_role.id
  policy = data.aws_iam_policy_document.mount_ebs_volumes.json
}

data "aws_iam_policy_document" "mount_ebs_volumes" {
  statement {
    effect = "Allow"

    actions = [
      "ec2:DescribeInstances",
      "ec2:DescribeTags",
      "ec2:DescribeVolumes",
      "ec2:AttachVolume",
      "ec2:DetachVolume",
    ]
    resources = ["*"]
  }
}

resource "aws_ebs_volume" "mysql" {
  availability_zone = aws_instance.client[0].availability_zone
  size              = 40
}

output "ebs_volume" {
    value = <<EOM
# volume registration
type        = "csi"
id          = "mysql"
name        = "mysql"
external_id = "${aws_ebs_volume.mysql.id}"
plugin_id   = "aws-ebs0"

capability {
  access_mode     = "single-node-writer"
  attachment_mode = "file-system"
}
EOM
}

terraform plan과 terraform apply를 실행해 새 IAM 정책과 EBS 볼륨을 만들어요. 그런 다음 terraform output ebs_volume > volume.hcl을 실행해요. 이 파일은 나중에 볼륨을 Nomad에 등록하는 데 사용할 거예요.

위 Terraform 구성에 대한 참고 사항 (Notes about the above Terraform configuration)
  • IAM 정책 문서와 역할 정책이 EC2 인스턴스의 기존 인스턴스 역할에 추가되고 있어요. 이 정책은 EC2 인스턴스가 Terraform에서 만든 볼륨을 마운트할 수 있게 하지만, 새 볼륨을 만들 수는 없게 해요.
  • EBS 볼륨 리소스는 나중에 CSI를 통해 연결할 데이터 볼륨이에요. 출력은 볼륨을 Nomad에 등록하는 데 사용될 거예요.

권한 있는 Docker 작업 활성화 (Enable privileged Docker jobs)

CSI Node 플러그인은 디스크를 기본 호스트에 마운트하기 위해 양방향 마운트 전파(bidirectional mount propagation)를 사용하므로 권한 있는(privileged) Docker 작업으로 실행되어야 해요.

node 또는 monolith 유형으로 실행되는 CSI 플러그인은 호스트에서 볼륨을 마운트하려면 루트 권한(Linux에서는 CAP_SYS_ADMIN)이 필요해요. Docker 작업 드라이버에서는 privileged = true 구성을 사용할 수 있지만, 현재 다른 기본 작업 드라이버에는 이 옵션이 없어요.

Nomad의 기본 구성은 권한 있는 Docker 작업을 허용하지 않으며, 허용하도록 편집해야 해요.

양방향 마운트 전파는 위험할 수 있고 호스트 운영 체제를 손상시킬 수 있어요. 이러한 이유로 권한 있는 컨테이너에서만 허용돼요.

활성화하려면 모든 Nomad 클라이언트의 구성을 편집하고 Docker 플러그인의 구성 안에서 allow_privileged를 true로 설정해요. 새 구성을 로드하려면 Nomad 클라이언트 프로세스를 다시 시작해요.

Nomad 클라이언트 구성에 Docker 플러그인 구성이 이미 지정되어 있지 않다면 이 최소 구성이 권한 있는 컨테이너를 허용할 거예요. Nomad 클라이언트 구성에 추가하고 Nomad를 다시 시작해요.

  config {
    allow_privileged = true
  }
}

권한 있는 컨테이너가 호스트에서 마운트를 수행하지 못하게 하는 특정 Docker 구성이 있을 수 있어요. 오류 메시지에는 "linux mounts: path ... is mounted on ... but it is not a shared mount"라는 문구가 포함될 가능성이 높아요. 자세한 내용은 Docker 포럼에서 찾을 수 있어요.

Nomad에서 권한 있는 컨테이너를 활성화하지 않았다면 plugin-aws-ebs-nodes 작업을 제출할 때 다음 오류를 받게 될 거예요:

"amazon/aws-ebs-csi-driver:v0.10.1": Docker privileged mode is disabled on this
Nomad agent

EBS 플러그인 배포 (Deploy the EBS plugin)

CSI용 플러그인은 plugin 스탠자가 있는 Nomad 작업으로 실행돼요. AWS EBS용 공식 플러그인은 GitHub의 aws-ebs-csi-driver 리포지토리에서 찾을 수 있어요. Docker 작업 드라이버로 실행할 수 있는 Docker 컨테이너로 패키징되어 있어요.

각 CSI 플러그인은 하나 이상의 유형을 지원해요: Controllers와 Nodes. 플러그인의 Node 인스턴스는 볼륨을 마운트하려는 모든 Nomad 클라이언트 노드에서 실행되어야 해요. Node 플러그인 인스턴스는 Nomad system 작업으로 실행하는 것이 좋아요. 일부 플러그인은 모든 Nomad 클라이언트 노드에서 실행될 수 있는 조정용 Controller 인스턴스도 필요해요.

AWS EBS 플러그인은 EBS 볼륨에 대한 접근을 조정할 컨트롤러 플러그인과 볼륨을 EC2 인스턴스에 마운트할 노드 플러그인이 필요해요. 컨트롤러 작업은 nomad service 작업으로, 노드 작업은 Nomad system 작업으로 만들 거예요.

plugin-ebs-controller.nomad.hcl이라는 이름의 컨트롤러 작업 파일을 다음 내용으로 만들어요.

  datacenters = ["dc1"]

  group "controller" {
    task "plugin" {
      driver = "docker"

      config {
        image = "amazon/aws-ebs-csi-driver:v0.10.1"

        args = [
          "controller",
          "--endpoint=unix://csi/csi.sock",
          "--logtostderr",
          "--v=5",
        ]
      }

      csi_plugin {
        id        = "aws-ebs0"
        type      = "controller"
        mount_dir = "/csi"
      }

      resources {
        cpu    = 500
        memory = 256
      }
    }
  }
}

plugin-ebs-nodes.nomad.hcl이라는 이름의 노드 작업 파일을 다음 내용으로 만들어요.

  datacenters = ["dc1"]

  # you can run node plugins as service jobs as well, but this ensures
  # that all nodes in the DC have a copy.
  type = "system"

  group "nodes" {
    task "plugin" {
      driver = "docker"

      config {
        image = "amazon/aws-ebs-csi-driver:v0.10.1"

        args = [
          "node",
          "--endpoint=unix://csi/csi.sock",
          "--logtostderr",
          "--v=5",
        ]

        # node plugins must run as privileged jobs because they
        # mount disks to the host
        privileged = true
      }

      csi_plugin {
        id        = "aws-ebs0"
        type      = "node"
        mount_dir = "/csi"
      }

      resources {
        cpu    = 500
        memory = 256
      }
    }
  }
}

플러그인 작업 배포 (Deploy the plugin jobs)

nomad job run plugin-ebs-controller.nomad.hcl과 nomad job run plugin-ebs-nodes.nomad.hcl로 두 작업을 모두 배포해요. 작업 자체가 실행된 후 플러그인이 Nomad에 정상으로 등록되는 데 몇 분 정도 걸려요. nomad plugin status 명령으로 플러그인 상태를 확인할 수 있어요.

플러그인에는 네임스페이스가 없지만, 플러그인을 시작한 작업에는 네임스페이스가 있다는 점을 참고해요. 플러그인은 Nomad 클라이언트와 같은 방식으로 클러스터 전체에서 사용할 수 있는 리소스로 취급돼요.

ID                         Type     Priority  Status   Submit Date
plugin-aws-ebs-controller  service  50        running  2020-03-20T10:49:13-04:00
plugin-aws-ebs-nodes       system   50        running  2020-03-20T10:49:17-04:00
ID                   = aws-ebs0
Provider             = ebs.csi.aws.com
Version              = v0.10.1
Controllers Healthy  = 1
Controllers Expected = 1
Nodes Healthy        = 2
Nodes Expected       = 2

Allocations
ID        Node ID   Task Group  Version  Desired  Status   Created    Modified
de2929cc  ac41c184  controller  0        run      running  1m26s ago  1m8s ago
d1d4831e  ac41c184  nodes       0        run      running  1m22s ago  1m18s ago
2b815e02  b896731a  nodes       0        run      running  1m22s ago  1m14s ago

볼륨 등록 (Register the volume)

CSI 플러그인은 관리하는 각 볼륨에 대해 알림을 받아야 하므로, 각 볼륨에 대해 nomad volume register를 실행해요. 앞서 Terraform으로 볼륨 정의가 포함된 volume.hcl 파일을 출력했어요.

ID                   = mysql
Name                 = mysql
External ID          = vol-0b756b75620d63af5
Plugin ID            = aws-ebs0
Provider             = ebs.csi.aws.com
Version              = v0.10.1
Schedulable          = true
Controllers Healthy  = 1
Controllers Expected = 1
Nodes Healthy        = 2
Nodes Expected       = 2
Access Mode          = <none>
Attachment Mode      = <none>
Mount Options        = <none>
Namespace            = default

Allocations
No allocations placed

위 볼륨 상태 출력은 볼륨이 스케줄링될 준비가 됐지만 현재 사용하는 할당이 없음을 나타내요.

MySQL 배포 (Deploy MySQL)

작업 파일 만들기 (Create the job file)

이제 스토리지에 Nomad 호스트 볼륨을 사용할 수 있는 MySQL 데이터베이스를 배포할 준비가 됐어요. mysql.nomad.hcl이라는 파일을 만들고 다음 내용을 제공해요.

  datacenters = ["dc1"]
  type        = "service"

  group "mysql-server" {
    count = 1

    volume "mysql" {
      type            = "csi"
      read_only       = false
      source          = "mysql"
      access_mode     = "single-node-writer"
      attachment_mode = "file-system"
    }

    network {
      port "db" {
        static = 3306
      }
    }

    restart {
      attempts = 10
      interval = "5m"
      delay    = "25s"
      mode     = "delay"
    }

    task "mysql-server" {
      driver = "docker"

      volume_mount {
        volume      = "mysql"
        destination = "/srv"
        read_only   = false
      }

      env {
        MYSQL_ROOT_PASSWORD = "password"
      }

      config {
        image = "hashicorp/mysql-portworx-demo:latest"
        args  = ["--datadir", "/srv/mysql"]
        ports = ["db"]
      }

      resources {
        cpu    = 500
        memory = 1024
      }

      service {
        name = "mysql-server"
        port = "db"

        check {
          type     = "tcp"
          interval = "10s"
          timeout  = "2s"
        }
      }
    }
  }
}

위 작업 명세서에 대한 참고 사항 (Notes about the above job specification)

  • 서비스 이름은 mysql-server이며 나중에 데이터베이스에 연결하는 데 사용할 거예요.
  • read_only 인수는 읽기 전용 볼륨 마운트를 만들기 위해 변경해야 하는 모든 위치를 강조하기 위해 볼륨 관련 스탠자 전체에 제공돼요. 자세한 내용은 volume과 volume_mount 명세를 참조해요.
  • 메모리가 낮은 인스턴스의 경우 클러스터의 사용 가능한 리소스와 조화를 이루도록 resources 스탠자의 요청 메모리를 줄여야 할 수도 있어요.

작업 실행 (Run the job)

이전 단계에서 만든 작업 파일을 다음 명령으로 등록해요.

==> Monitoring evaluation "aa478d82"
    Evaluation triggered by job "mysql-server"
    Allocation "6c3b3703" created: node "be8aad4e", group "mysql-server"
    Evaluation status changed: "pending" -> "complete"
==> Evaluation "aa478d82" finished with status "complete"

할당 상태에 CSI 볼륨 섹션이 있고, 볼륨 상태에 볼륨을 요청하는 할당이 표시될 거예요.

CSI Volumes:
ID     Read Only
mysql  false
ID                   = mysql
Name                 = mysql
External ID          = vol-0b756b75620d63af5
Plugin ID            = aws-ebs0
Provider             = ebs.csi.aws.com
Version              = v0.10.1
Schedulable          = true
Controllers Healthy  = 1
Controllers Expected = 1
Nodes Healthy        = 2
Nodes Expected       = 2
Access Mode          = single-node-writer
Attachment Mode      = file-system
Mount Options        = <none>
Namespace            = default

Allocations
ID        Node ID   Task Group    Version  Desired  Status   Created    Modified
6c3b3703  ac41c184  mysql-server  3        run      running  1m40s ago  1m2s ago

MySQL에 데이터 쓰기 (Write data to MySQL)

MySQL 연결 (Connect to MySQL)

(앞서 설치한) mysql 클라이언트를 사용해 데이터베이스에 연결하고 정보에 접근해요.

이 데모 데이터베이스의 비밀번호는 password예요.

참고

이 튜토리얼은 데모용이며 데이터베이스 비밀번호 보안에 대한 모범 사례를 따르지 않아요. 자세한 내용은 비밀번호 보안 유지를 참조해요.

이 클러스터에는 Nomad와 함께 Consul이 설치되어 있으므로 작업 파일에서 작업에 등록한 mysql-server 서비스 이름을 사용해 연결할 수 있어요.

테스트 데이터 추가 (Add test data)

데이터베이스에 연결한 후 items 테이블이 존재하는지 확인해요.

+--------------------------+
| Tables_in_itemcollection |
+--------------------------+
| items                    |
+--------------------------+
1 row in set (0.00 sec)

다음 명령으로 이 테이블의 내용을 표시해요.

+----+----------+
| id | name     |
+----+----------+
|  1 | bike     |
|  2 | baseball |
|  3 | chair    |
+----+----------+
3 rows in set (0.00 sec)

이제 이 테이블에 데이터를 추가해요(Nomad에서 데이터베이스를 종료하고 다시 시작한 후에도 이 데이터는 그대로 있어야 해요).

다른 값으로 INSERT INTO 명령을 원하는 만큼 실행해요.

mysql> INSERT INTO items (name) VALUES ('keyboard');

완료되면 exit를 입력하고 Nomad 클라이언트 명령줄로 돌아가요.

Bye

데이터베이스 작업 제거 (Destroy the database job)

다음 명령을 실행해 클러스터에서 MySQL 작업을 중지하고 제거해요.

==> Monitoring evaluation "6b784149"
    Evaluation triggered by job "mysql-server"
    Evaluation status changed: "pending" -> "complete"
==> Evaluation "6b784149" finished with status "complete"

MySQL이 클러스터에서 더 이상 실행되지 않는지 확인해요.

No job(s) with prefix or id "mysql" found

다시 배포하고 확인 (Re-deploy and verify)

[앞서 만든]](/nomad/docs/stateful-workloads/csi-volumes#create-the-job-file) mysql.nomad.hcl 작업 파일을 사용해 데이터베이스를 Nomad 클러스터에 다시 배포해요.

==> Monitoring evaluation "61b4f648"
    Evaluation triggered by job "mysql-server"
    Allocation "8e1324d2" created: node "be8aad4e", group "mysql-server"
    Evaluation status changed: "pending" -> "complete"
==> Evaluation "61b4f648" finished with status "complete"

MySQL에 다시 연결하면 데이터베이스를 제거하기 전에 추가한 정보가 여전히 존재하는지 확인할 수 있어요.

+----+----------+
| id | name     |
+----+----------+
|  1 | bike     |
|  2 | baseball |
|  3 | chair    |
|  4 | glove    |
|  5 | hat      |
|  6 | keyboard |
+----+----------+
6 rows in set (0.00 sec)

정리 (Cleanup)

이 가이드를 완료한 후에는 다음 정리 단계를 수행해야 해요.

  • mysql-server 작업을 중지하고 제거해요.
  • nomad volume deregister mysql로 Nomad에서 EBS 볼륨 등록을 해제해요.
  • plugin-aws-ebs-controller와 plugin-aws-ebs-nodes 작업을 중지하고 제거해요.
  • terraform destroy로 EBS 볼륨을 제거해요.

요약 (Summary)

이 가이드에서는 Nomad에 CSI 플러그인을 배포하고, 해당 플러그인에 AWS EBS 볼륨을 등록했으며, 이 볼륨을 Docker MySQL 컨테이너에 마운트하는 작업을 만들어 작업 수명을 넘어 지속되는 데이터를 썼어요.

더 알아보기 (Learn more)