본문 바로가기

AWS EKS 실습/EKS Intermediate

Deploying Jenkins for Kubernetes

먼저 CodeCommit repository를 생성한다. 이 repository는 application code와 Jenkinsfile을 저장하기 위한 장소이다.

aws codecommit create-repository --repository-name eksworkshop-app
{
    "repositoryMetadata": {
        "repositoryName": "eksworkshop-app", 
        "cloneUrlSsh": "ssh://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/eksworkshop-app", 
        "lastModifiedDate": 1616109672.528, 
        "repositoryId": "826bfbfd-2a75-4242-ac8d-87ad614193fd", 
        "cloneUrlHttp": "https://git-codecommit.ap-northeast-2.amazonaws.com/v1/repos/eksworkshop-app", 
        "creationDate": 1616109672.528, 
        "Arn": "arn:aws:codecommit:ap-northeast-2:221745184950:eksworkshop-app", 
        "accountId": "221745184950"
    }
}

 

AWS CodeCommit에 대한 HTTPS Git 자격증명을 갖은 IAM 사용자를 생성하여 Repository로 복제하고 추가 Commit을 Push 한다. 이 사용자는 CodeCommit에 엑세스를 위한 IAM Policy를 필요로 한다.

 

aws iam create-user \
  --user-name git-user

aws iam attach-user-policy \
  --user-name git-user \
  --policy-arn arn:aws:iam::aws:policy/AWSCodeCommitPowerUser

aws iam create-service-specific-credential \
  --user-name git-user --service-name codecommit.amazonaws.com \
  | tee /tmp/gituser_output.json

GIT_USERNAME=$(cat /tmp/gituser_output.json | jq -r '.ServiceSpecificCredential.ServiceUserName')
GIT_PASSWORD=$(cat /tmp/gituser_output.json | jq -r '.ServiceSpecificCredential.ServicePassword')
CREDENTIAL_ID=$(cat /tmp/gituser_output.json | jq -r '.ServiceSpecificCredential.ServiceSpecificCredentialId')

 

적용 결과는 다음과 같다.

{
    "User": {
        "UserName": "git-user", 
        "Path": "/", 
        "CreateDate": "2021-03-18T23:24:41Z", 
        "UserId": "AIDATHIILAC3KMDOJ7XH5", 
        "Arn": "arn:aws:iam::221745184950:user/git-user"
    }
}
eksuser:~/environment $ aws iam attach-user-policy \
>   --user-name git-user \
>   --policy-arn arn:aws:iam::aws:policy/AWSCodeCommitPowerUser
eksuser:~/environment $ 
eksuser:~/environment $ aws iam create-service-specific-credential \
>   --user-name git-user --service-name codecommit.amazonaws.com \
>   | tee /tmp/gituser_output.json
{
    "ServiceSpecificCredential": {
        "UserName": "git-user", 
        "Status": "Active", 
        "CreateDate": "2021-03-18T23:36:01Z", 
        "ServiceName": "codecommit.amazonaws.com", 
        "ServicePassword": "ViyHMvMSbBEUmCq7f7QbFuQ3f8ngDmcmnjzyLexrtQU=", 
        "ServiceSpecificCredentialId": "ACCATHIILAC3BSHPEOUCB", 
        "ServiceUserName": "git-user-at-221745184950"
    }
}

 

Repository에는 몇가지 초기 Code가 필요하므로 repository를 clone하고 간단한 Go Application을 추가한다.

sudo pip install git-remote-codecommit
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip install --user` instead.
Collecting git-remote-codecommit
  Using cached https://files.pythonhosted.org/packages/1f/82/7c22f218a7fd3177def489febc9b8c262a3b2bcb6785d05e15d435ddcab8/git-remote-codecommit-1.15.1.tar.gz
Requirement already satisfied: botocore>=1.17.0 in /usr/lib/python2.7/site-packages (from git-remote-codecommit)
Requirement already satisfied: urllib3<1.27,>=1.25.4 in /usr/lib/python2.7/site-packages (from botocore>=1.17.0->git-remote-codecommit)
Requirement already satisfied: jmespath<1.0.0,>=0.7.1 in /usr/lib/python2.7/site-packages (from botocore>=1.17.0->git-remote-codecommit)
Requirement already satisfied: python-dateutil<3.0.0,>=2.1 in /usr/lib/python2.7/site-packages (from botocore>=1.17.0->git-remote-codecommit)
Requirement already satisfied: six>=1.5 in /usr/lib/python2.7/site-packages (from python-dateutil<3.0.0,>=2.1->botocore>=1.17.0->git-remote-codecommit)
Installing collected packages: git-remote-codecommit
  Running setup.py install for git-remote-codecommit ... done
Successfully installed git-remote-codecommit-1.15.1
git clone codecommit::${AWS_REGION}://eksworkshop-app
Cloning into 'eksworkshop-app'...
warning: You appear to have cloned an empty repository.

 

Sample server.go 프로그램을 작성한다.

cat << EOF > server.go

package main

import (
    "fmt"
    "net/http"
)

func helloWorld(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w, "Hello World")
}

func main() {
    http.HandleFunc("/", helloWorld)
    http.ListenAndServe(":8080", nil)
}
EOF

Sampe server_test.go 프로그램을 작성한다.

cat << EOF > server_test.go

package main

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

func Test_helloWorld(t *testing.T) {
	req, err := http.NewRequest("GET", "http://domain.com/", nil)
	if err != nil {
		t.Fatal(err)
	}

	res := httptest.NewRecorder()
	helloWorld(res, req)

	exp := "Hello World"
	act := res.Body.String()
	if exp != act {
		t.Fatalf("Expected %s got %s", exp, act)
	}
}

EOF

 

The Jenkinsfile will contain our pipeline declaration, the additional containers in our build agent pods, and which container will be used for each step of the pipeline.

 

cat << EOF > Jenkinsfile
pipeline {
  agent {
    kubernetes {
      yaml """
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: golang
    image: golang:1.13
    command:
    - cat
    tty: true
"""
    }
  }
  stages {
    stage('Run tests') {
      steps {
        container('golang') {
          sh 'go test'
        }
      }
    }
    stage('Build') {
        steps {
            container('golang') {
              sh 'go build -o eksworkshop-app'
              archiveArtifacts "eksworkshop-app"
            }
            
        }
    }
    
  }
}

EOF

 

위에서 생성한 code를 repository에 commit 하고 push 한다.

git add --all && git commit -m "Initial commit." && git push
cd ~/environment

 

Kuberenetes가 CodeCommit API 작업을 수행해야 하는 경우 Pod에 부여할 서비스 계정을 생성해야 한다. 이를 통해 Jenkins는 새로운 repository, branch, commit을 수행할 수 있다.

 

먼저 eks cluster를 위한 OIDC identity provider를 생성한다.

eksctl utils associate-iam-oidc-provider --cluster eksworkshop-eksctl --approve

 

이제 iamserviceaccount를 생성한다. 

eksctl create iamserviceaccount \
    --name jenkins \
    --namespace default \
    --cluster eksworkshop-eksctl \
    --attach-policy-arn arn:aws:iam::aws:policy/AWSCodeCommitPowerUser \
    --approve \
    --override-existing-serviceaccounts

 

ㅁ Deploy Jenkins

 

Jenkins installation의 configuration을 선언하기 위하여 values.yaml을 생성한다.

cat << EOF > values.yaml
---
master:
  additionalPlugins:
    - aws-codecommit-jobs:0.3.0
  resources:
    requests:
      cpu: "1024m"
      memory: "4Gi"
    limits:
      cpu: "4096m"
      memory: "8Gi"
  javaOpts: "-Xms4000m -Xmx4000m"
  servicePort: 80
  serviceType: LoadBalancer
agent:
  Enabled: false
rbac:
  create: true
serviceAccount:
  create: false
  name: "jenkins"
EOF

 

value.yaml을 사용하여 helm으로 jenkins를 설치한다.

helm install cicd stable/jenkins -f values.yaml

 설치를 진행하면 admin password 와 ELB의 호스트 이름을 가져오는 방법과 같은 몇가지 추가적인 정보를 제공한다.

 

kubectl get pods -w

NAME                           READY   STATUS    RESTARTS   AGE
cicd-jenkins-7854d9569-xxd7c   2/2     Running   0          5m14s

를 해보면 pod의 상태를 볼수 있다. 이 후 아래 명령어를 통해 jenkins 접근 url을 확인한다.

export SERVICE_IP=$(kubectl get svc --namespace default cicd-jenkins --template "{{ range (index .status.loadBalancer.ingress 0) }}{{ . }}{{ end }}")

echo http://$SERVICE_IP/login

정상적으로 Jenkin 로그인 화면이 뜨면 된다.

 

로그인을 위한 user name은 admin이며 password는 아래 명령어를 통해 확인한다.

 

printf $(kubectl get secret --namespace default cicd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo

 

'AWS EKS 실습 > EKS Intermediate' 카테고리의 다른 글

Implement Logging with EFK  (0) 2021.03.19
CI/CD with CodePipeline (다시 볼것)  (0) 2021.03.19
Advanced POD CPU and Memory management  (0) 2021.03.18
Pod Priority And Preemption  (0) 2021.03.18
Resource Quotas  (0) 2021.03.18