AWS

Deploy Selenium to the AWS Machine

kahnco 2023. 11. 18. 22:39

요구사항

  1. Selenium Grid를 AWS Machine (ex. EC2, ECS, EKS 등등)에 배포하기
  2. 배포된 Selenium을 외부에서 접근해서 사용하기

실패한 이력들

1. EC2

https://github.com/SeleniumHQ/docker-selenium/blob/trunk/docker-compose-v3.yml
간단하게 docker-compose로 구성된 위 파일을 그대로 EC2에 배포해서 테스트 해보았다.
 

docker-compose -f docker-compose-v3.yml up -d

 
 EC2 인스턴스는 Ubuntu 22.04 버전을 사용하였으며, 보안 그룹으로 3000-8000의 포트들을 모든 Ipv4 주소에 열어놓았다. 그리고 해당 Selenium을 테스트하는 코드는 다음과 같이 Python으로 간단하게 작성하였다.
 

from selenium import webdriver


def test_start_remote(server):
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    options.add_argument("--no-sandbox")

    driver = webdriver.Remote(command_executor=server, options=options)
    driver.get("https://google.com")
    print(driver.title)
    driver.quit()


if __name__ == '__main__':
    test_start_remote("http://{EC2_IP_ADDRESS}:4444/wd/hub")

 
 remote url을 위 코드와 같이 사용 해보기도 하고, ID/PW를 admin:admin 으로 붙여서 사용 해보았으나 Timeout, 즉 연결 실패했다.
 
 docker logs 명령어로 selenium-hub 노드의 로그를 확인해보니 각 브라우저의 노드들과 연동은 되었으나 외부의 트래픽이 아예 접근조차 못하고 있었다.
 

2. ECS

https://github.com/MummanaSubramanya/selenium-grid4-ecs-fargate

 

GitHub - MummanaSubramanya/selenium-grid4-ecs-fargate: Selenium Grid 4 on Fargate

Selenium Grid 4 on Fargate. Contribute to MummanaSubramanya/selenium-grid4-ecs-fargate development by creating an account on GitHub.

github.com

https://github.com/taktakpeops/selenium-grid-ecs-fargate

 

GitHub - taktakpeops/selenium-grid-ecs-fargate: A Selenium Grid deployed in ECS Fargate

A Selenium Grid deployed in ECS Fargate. Contribute to taktakpeops/selenium-grid-ecs-fargate development by creating an account on GitHub.

github.com

 위와 같이 다양한 예제들을 사용했으나 이 역시 EC2와 마찬가지로 접근이 불가능했다. 또한 일부 예제들은 아예 selenium-hub 서비스와 browser 서비스들간의 통신이 안되는 케이스가 많아서 보안그룹을 억지로 붙여줘야했다.
 
 기왕 ECS를 사용하는 김에 IaC 를 살려서 CDK로 배포하고자 했으나, selenium hub service와 browser service간의 보안 그룹을 붙여주는 과정에 다음과 같은 이슈까지 발견하고 말았다.
 
https://github.com/aws/aws-cdk/issues/5635

 

addSecurityGroup didn't work for ECS_pattern ALB Fargate · Issue #5635 · aws/aws-cdk

I was not able to add another security group to the ECS Pattern for ALB Fargate service using Fargate.cluster.connections.addSecurityGroup() method. Reproduction Steps ecs-fargate.ts export class E...

github.com

 
 ApplicationLoadBalancedFargateService 객체를 활용해서 Selenium hub Service를 ALB에 붙여서 바로 배포하려고 했으나 해당 객체에 보안 그룹을 커스텀할 수 없다는 이슈가 있었다. 이를 해결하기 위해 ApplicationLoadBalancer 객체와 FargateService를 직접 생성해서 연결시켜주는 방법으로 구현을 했으나, 이렇게 구현한 ECS Selenium 역시 외부에서 접근이 불가능했다.


성공한 이력

AWS EKS

 EC2도 실패하고, ECS도 실패하였으니 남은건 EKS 뿐이었다.
 
 일단 eksctl를 활용해서 정말 간단하게 EKS Cluster를 배포해주었다.

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: selenium-k8s-cluster
  region: ap-northeast-2
  version: "1.27"

nodeGroups:
  - name: selenium-k8s-nodegroup
    instanceType: t3.medium
    desiredCapacity: 2

 
 NodeGroup의 타입은 t3.medium으로 지정해주었고, 노드 개수는 2개로 지정해주었다.
 
 그리고 EC2에서 사용했던 SeleniumHQ 쪽의 git repository에서 helm 차트를 활용한 selenium grid 배포 가이드가 있어서 그대로 사용해보았다.
 
https://github.com/SeleniumHQ/docker-selenium/tree/trunk/charts/selenium-grid
 
 이 과정에서 문제가 발생했는데, 이를 그대로 활용하면 selenium brower node의 concurrency가 겨우 1개로 할당되어서 도저히 사용할 수 없는 수준이었다. 따라서, concurrency를 수정하는 과정이 필요했는데, 이는 해당 concurrency 설정 부분을 따로 yaml 파일로 작성해서 helm install 과정에서 추가해주는 방식으로 해결하였다.
 

// extraEnvironmentVariables.yaml
chromeNode:
  extraEnvironmentVariables:
    - name: "SE_NODE_OVERRIDE_MAX_SESSIONS"
      value: "true"
    - name: "SE_NODE_MAX_SESSIONS"
      value: "64"
    - name: "JAVA_OPTS"
      value: "-XX:ActiveProcessorCount=64"
    - name: "START_XVFB"
      value: "false"
# Install Selenium Grid With Helm Chart
kubectl create namespace selenium
helm repo add docker-selenium https://www.selenium.dev/docker-selenium
helm repo update
helm search repo docker-selenium --versions

helm install selenium-grid --namespace selenium docker-selenium/selenium-grid \
--set chromeNode.enabled="true" \				# chrome node만 사용
--set chromeNode.replicas="2" \					# 개수 2개
--set firefoxNode.enabled="false" \				# firefox node 미사용
--set firefoxNode.deploymentEnabled="false" \	# firefox node 미사용
--set edgeNode.enabled="false" \				# edge node 미사용
--set edgeNode.deploymentEnabled="false" \		# edge node 미사용
-f extraEnvironmentVariables.yaml				# chrome node의 concurrency 수정

 
 여기까지 진정하고, 배포된 Selenium Hub Service에 접근하기 위해서 Load Balancer를 추가해주는 과정이 필요했다. 이를 위해 기존에 세팅된 EKS에 aws iam oidc provider를 설치하고 eks/aws-load-balancer-controller 플러그인을 helm으로 설치해주는 과정이 필요했다.
 

# Create a service account for AWS IAM Authenticator
eksctl utils associate-iam-oidc-provider --cluster selenium-k8s-cluster --approve
curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.3.1/docs/install/iam_policy.json

aws iam create-policy \
    --policy-name AWSLoadBalancerControllerIAMPolicy \
    --policy-document file://iam-policy.json
    
eksctl create iamserviceaccount \
    --cluster=selenium-k8s-cluster \
    --namespace=kube-system \
    --name=aws-load-balancer-controller \
    --attach-policy-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy \
    --override-existing-serviceaccounts \
    --approve
    
helm repo add eks https://aws.github.io/eks-charts
helm repo update
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
    -n kube-system \
    --set clusterName=selenium-k8s-cluster \
    --set serviceAccount.create=false \
    --set serviceAccount.name=aws-load-balancer-controller \
    --set image.repository=602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon/aws-load-balancer-controller \
    --set region=ap-northeast-2 \
    --set vpcId=${VPC_ID}

# Check the status of the deployment
kubectl get deployment -n kube-system aws-load-balancer-controller

 
  이렇게 세팅해놓고, alb-ingress를 eks에 배포해주면 자동으로 ALB가 생성된다. ALB 생성을 위해서 사용한 alb-ingress 코드는 다음과 같다.
 

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: "selenium-ingress"
  namespace: selenium
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/group.name: selenium-ingress-group
    alb.ingress.kubernetes.io/group.order: '1'
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}, {"HTTP":4442}, {"HTTP":4443}, {"HTTP":4444}]'
    alb.ingress.kubernetes.io/certificate-arn: {AWS_ACM_ARN}
    alb.ingress.kubernetes.io/ssl-redirect: '443'
    alb.ingress.kubernetes.io/idle-timeout: '300'
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: "/"
            pathType: Prefix
            backend:
              service:
                name: "selenium-hub"
                port:
                  number: 4444
# Deploy Ingress Controller
kubectl apply -f selenium-ingress.yaml

 
 여기까지 진행하면, AWS의 로드 밸런서 콘솔에서 새로 생성된 ALB를 확인할 수 있다. 해당 ALB의 DNS 주소를 활용해서 아까 위에서 사용했던 Python 코드를 그대로 사용해면 다음과 같이 정상적인 결과값을 얻을 수 있다.
 

from selenium import webdriver


def test_start_remote(server):
    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    options.add_argument("--no-sandbox")

    driver = webdriver.Remote(command_executor=server, options=options)
    driver.get("https://google.com")
    print(driver.title)
    driver.quit()


if __name__ == '__main__':
    test_start_remote("http://admin:admin@{ALB_DNS_ADDRESS}/wd/hub")

 

성공

 
저기 URL에서 ID/PW 값(admin:admin) 없이 실행하면 실패하게 되는데, 나는 분명히 따로 설정해둔 인증 값이 없는데 있는 걸 보면 기존값으로 등록되어있는 값인 것 같다.


결과

  1. EC2/ECS로는 실패
  2. EKS로는 selenium hub의 k8s service type을 loadBalancer로 잡으면 실패하고, default type 선택 이후에 따로 Ingress ALB를 생성해주면 성공하는 것을 보니 EC2/ECS의 실패 또한 방화벽, 라우팅의 문제인 것 같다.
반응형

'AWS' 카테고리의 다른 글

[WriterSide] Publishing and Access Control  (0) 2024.04.24
Make a Scheduler With AWS EventBridge  (0) 2023.11.21
AWS CDK - API Gateway Fix Note 1  (0) 2023.11.07