프로젝트/AWS Fargate in Jenkins

AWS Fargate를 사용해 jenkins master <-> agent를 구성해보자. Part 2.

Hwan2 2023. 4. 2. 22:54
반응형

 

 

 

 

목차.

 

 

 

이번장에선 AWS Fargate, Cloud Map, EFS 셋팅을 해보겠습니다.

 

우선 Fargate에서 사용할 Cloud Map를 구현합니다.

 

1. AWS Cloud Map

# Define Jenkins Cloud Map

resource "aws_service_discovery_private_dns_namespace" "jenkins" {
  name        = "local.com"
  vpc         = var.jenkins_vpc_id
  description = "Jenkins Cloud Map"

  tags = {
    Name = "Jenkins Cloud Map"
  }
}

resource "aws_service_discovery_service" "jenkins" {
  name = "jenkins"

  dns_config {
    namespace_id = aws_service_discovery_private_dns_namespace.jenkins.id

    dns_records {
      ttl  = 60
      type = "A"
    }

    routing_policy = "MULTIVALUE"
  }

  health_check_custom_config {
    failure_threshold = 1
  }

  tags = {
    Name = "Jenkins Cloud Map"
  }
}

 

Master와 Agent가 통신을 할 때 필요한 Private DNS 설정입니다.

내부적으로 사용될 DNS이므로, 도메인 등록, DNS validation 과정은 필요 없습니다.

 

2. AWS EFS

# Define Jenkins EFS

resource "aws_efs_file_system" "jenkins" {
  creation_token = "jenkins-efs"

  tags = {
    Name = "Jenkins EFS"
  }
}

resource "aws_efs_mount_target" "jenkins" {
  for_each       = var.jenkins_vpc_private_subnet_ids
  file_system_id = aws_efs_file_system.jenkins.id
  subnet_id      = each.value
  security_groups = [
    var.jenkins_efs_sg_id
  ]
}

resource "aws_efs_access_point" "jenkins" {
  file_system_id = aws_efs_file_system.jenkins.id

  posix_user {
    uid = 1000
    gid = 1000
  }
  root_directory {
    path = "/jenkins-home"

    creation_info {
      owner_gid   = 1000
      owner_uid   = 1000
      permissions = "0755"
    }
  }

  tags = {
    Name = "Jenkins EFS Access Point"
  }
}

 

위와 같이 EFS를 정의합니다. aws_efs_access_point의 root_directory에 있는 path는 마운트할 때 지정된 경로이므로 자유롭게 설정하면 됩니다.

 

해당 access point를 사용해 Fargate가 EFS에 접근할 수 있게 됩니다.

 

3. AWS ECS Fargate

ECS Fargate를 사용하여 Master <-> Agent 구조를 만듭니다.

 

resource "aws_ecs_cluster" "jenkins" {
  name = "jenkins-cluster"

  setting {
    name  = "containerInsights"
    value = "enabled"
  }

  tags = {
    Name = "Jenkins ECS Cluster"
  }
}

resource "aws_ecs_task_definition" "jenkins" {
  for_each                 = var.jenkins_tasks
  family                   = each.value.family
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = 1024
  memory                   = 2048
  execution_role_arn       = var.jenkins_ecs_task_execution_role_arn
  task_role_arn            = var.jenkins_ecs_task_role_arn

  container_definitions = jsonencode([
    {
      name      = each.key
      image     = each.value.image
      essential = true
      portMappings = [
        {
          containerPort = var.jenkins_port
          hostPort      = var.jenkins_port
          protocol      = "tcp"
        },
        {
          containerPort = var.jenkins_jnlp
          hostPort      = var.jenkins_jnlp
          protocol      = "tcp"
        },
        {
          containerPort = var.http
          hostPort      = var.http
          protocol      = "tcp"
        },
        {
          containerPort = var.https
          hostPort      = var.https
          protocol      = "tcp"
        }
      ]
      logConfiguration = {
        logDriver = "awslogs"
        options = {
          awslogs-group         = aws_cloudwatch_log_group.jenkins_ecs.name
          awslogs-region        = "ap-northeast-2"
          awslogs-stream-prefix = each.value.awslogs_prefix
        }
      }
      mountPoints = [
        {
          containerPath = "/var/jenkins_home"
          sourceVolume  = "jenkins_home"
        }
      ]
    }
  ])

  volume {
    name = "jenkins_home"

    efs_volume_configuration {
      file_system_id     = var.jenkins_efs_id
      transit_encryption = "ENABLED"

      authorization_config {
        access_point_id = var.jenkins_efs_access_point_id
        iam             = "ENABLED"
      }
    }
  }
}

resource "aws_ecs_service" "jenkins" {
  name                               = "jenkins-service"
  cluster                            = aws_ecs_cluster.jenkins.id
  task_definition                    = aws_ecs_task_definition.jenkins["jenkins-master"].arn
  desired_count                      = 1
  launch_type                        = "FARGATE"
  deployment_maximum_percent         = 100
  deployment_minimum_healthy_percent = 0

  network_configuration {
    subnets          = local.private_subnets
    security_groups  = [var.jenkins_ecs_sg_id]
    assign_public_ip = false
  }

  load_balancer {
    target_group_arn = var.jenkins_alb_target_group_arn
    container_name   = "jenkins-master"
    container_port   = var.jenkins_port
  }

  service_registries {
    registry_arn = var.jenkins_discovery_service_arn
  }

  tags = {
    Name = "Jenkins ECS Service"
  }
}

 

Task definition 을 정의할 때 Mount할 EFS를 등록해 줍니다.

 

그리고 ECS Service의 service_registries에 Cloud Map에 정의한 discovery service 정보를 넣어줍니다.

 

discovery service는 Amazon Route 53에서 사용할 수 있는 서비스 디스커버리를 통해 자동으로 검색하고 연결할 수 있도록 도와주는 구성 요소입니다.

이걸 ECS에 적용시키면 Docker간 통신을 IP주소 없이 Domain name으로 통신할 수 있게 됩니다.

 

 

정상적으로 ECS에 등록이 되면 위 사진과 같이 Route 53에 호스팅 영역으로 만든 이름이 나오게 됩니다.

 

그 외 Master <-> Agent와 통신할 수 있도록 8080, 50000포트를 열어둔 후 ECS에서 사용할 IAM rule, policy를 설정한 후 구성하면 됩니다.

 

여기서 추가적인 코드를 참고하시기 바랍니다.

 

https://github.com/dnfwlq8054/jenkins_in_fargate

 

GitHub - dnfwlq8054/jenkins_in_fargate: AWS ECS Fargate to set up a Jenkins master and agent structure.

AWS ECS Fargate to set up a Jenkins master and agent structure. - GitHub - dnfwlq8054/jenkins_in_fargate: AWS ECS Fargate to set up a Jenkins master and agent structure.

github.com

 

 

Route 53에 외부에서 사용할 도메인을 구매하지 않았기 때문에, 80포트로 ALB DNS주소에 접속합니다.

 

처음 비밀번호는 Cloud Watch에 log를 보면 확인이 가능 합니다.

 

ALB에 나와있는 DNS name으로 http 접속을 합니다.

이렇게 하면 구축한 jenkins에 접속할 수 있습니다.

 

다음 Part 3에서는 Agent를 실행하는 설정과 방법에 대해 설명하겠습니다.

 

반응형