알면서 귀찮아서 안했던 작업

 

AWS쓰면 CodeDeploy 통해서 그나마 쉽게 할 수 있을것 같은데,

젠킨스 써도 쉽게 할 수 있겠지?

 

젠킨스에서 쉽게 하는 방법 저는 잘 몰라용.

그냥 서버 여러군데 배포할때 한방에 하는 방법

여러개 돌아가며 누르는것도 괜찮지만, 그것마저 귀찮은게 사람이니까.

특히나, L4 스위칭까지 하려면 여간 귀찮은게.

 

물론 git에서 웹훅 날려서 하는 방법도 있긴한데, 막 모델이나 데이터 같은거 변경되었을때 이러면 위험하니까

클릭으로 하는 방법!

요거 하나 누르면 땡!

 

일단 현재 회사에서는 L4에서 특정 REST API의 상태값을 통해 연결할지 말지 여부를 결정짓는다.

그래서 해당 상태값을 "점검"으로 바꿔주면 해당 WAS로 연결은 끊기고 배포가 가능하다는 점.

 

젠킨스에서 보통 프로젝트 만들어서 하는 것과 과정은 유사하다.

  1. Git Clone
  2. 빌드
  3. 배포 및 실행

여러 WAS에 배포하기 위해 상태를 확인하고, 변경하는 작업이 추가로 들어가면 될것 같다.

 

젠킨스에서 제공해주는 파이프라인 스크립트는 두가지 방식으로 작성 할 수 있다.

  • 선언적 파이프라인 => 여기선 이걸로 진행한다. pipeline { } 이 감싸고 있음.
  • 스크립티드 파이프라인(노드) => 얘가 뭔가 간단해 보이는데, 담에 시간날때 시도해 봐야지, 다음 생에...

 

New Item 해서 Pipeline 선택하고 다음으로 넘어가면! Pipeline 란 하단에 Pipeline Syntax 라는 링크가 있다. 요 녀석을 눌러서 페이지에 가보면 파이프라인 스크립트 작성에 도움을 주는 툴이 있는걸 확인 할 수 있다. 제네레이터.

 

기본적은 스크립트는 위 처럼 자동으로 생성 할 수 있다.

  • agent
    • 스크립트를 실행할 에이전트를 지정하는데, 라벨로 지정이 가능하며, any로 하면 그냥 됨.
  • 구조
    • stages > stage > steps 이며, 별도로 jenkins에서 제공해주는, environment, tools 등을 사용 할 수 있다.
    • 이 부분은 Declarative Directive Generator 에서 생성 가능하다.
    • tools 같은게, 선언적 파이프라인과 스크립티드 파이프라인에서 쓰는 작성 법이 다르더라.
    • 각 스테이지의 이름은 알아보기 쉽게 작성하는게 좋긴하다.
    • Git Clone과 Publish on SSH에서 사용하는 Credential 관련된 정보는 사전에 등록해두면 제네레이터에서 사용 가능하다.
  • Git Clone 작성

제네레이터를 이용해 작성해 보자, 빈칸만 채우면 된다.

  • 빌드
    • 위와 마찬가지로 제네레이터를 이용해 tools의 Gradle을 사용하는 방법도 있지만, gradlew를 사용하면 더 편하다.
    • 보통 젠킨스가 설치된 서버 특성상 자바 버전도 여러개 일거고, 그런거 선택 자체를 gradlew 안에 넣어두면 더 용이하다.
  • 체크 및 스위칭 
    • 이건 CURL을 활용해서 하면 된다.
    • 결국 쉘 스크립트를 실행하는건데, 제네레이터의 script를 써서 쉘을 실행 할 수 있다.(groovy 문법이라고 한다. 얼핏 본거 같은데...)
    • 추가적으로 curl을 통해 얻어오는 Json값을 어떻게 가져올까 하고 grep 명령어 옵션을 엄청 찾았는데, jq 라는 간단한 커맨드 처리자가 있다. 대부분의 OS를 지원하고, 사용법도 간단하다. https://stedolan.github.io/jq/
script{         
    TOKEN = sh (
        script: '''
            curl -X POST "https://domain/user/sign-in" -H "Content-Type: application/json" -d '{"email":"email@account.com", "password":"xxxxxxxx", "remember": "false"}' | jq '.response.accessToken'
        ''',
        returnStdout: true
    ).trim()
}
  • 배포
    • 배포는 젠킨스의 publish on ssh를 사용했다.
    • 물론, 이것도 제네레이터를 사용해 작성 가능하다.
sshPublisher(
    publishers: 
        [
            sshPublisherDesc(
                configName: '설정된 SSH 접속 대상 서버 이름', 
                transfers: 
                    [
                        sshTransfer(
                            cleanRemote: false, 
                            excludes: '', 
                            execCommand: '''
                                            bash deploy.sh // 실행할 쉘 내용?
                                        ''', 
                            execTimeout: 120000, 
                            flatten: false, 
                            makeEmptyDirs: false, 
                            noDefaultExcludes: false, 
                            patternSeparator: '[, ]+', 
                            remoteDirectory: '파일을 업로드 할 폴더', 
                            remoteDirectorySDF: false, 
                            removePrefix: 'build/libs', // 제거할 프리픽스
                            sourceFiles: 'build/libs/result.jar' // 업로드할 파일
                        )
                    ], 
                usePromotionTimestamp: false, 
                useWorkspaceInPromotion: false, 
                verbose: true // 과정을 로그로 출력한다.
                )
        ]
    )

처음 해보면 어려울 수도 있겠지만, 단계적 절차를 밟아가며 수정 보완하며 작성하다보면 결국 잘 되기 마련이다.

이러한 파이프라인 코드를 Git에 올려두고 수정 & 사용 하는 것도 가능하다.

 

  • 작성 결과
pipeline {
    agent any

    stages {
        
        stage('git clone') {
            steps {
                git branch: '${branch}', credentialsId: '${credentialsId}', url: '${git_url}'
            }
        }
        
        stage('build') {
            steps{
                sh '''
                    echo build start
                    ./gradlew clean build
                    echo build end
                '''
            }
        }
        
        stage('get Token') {
            steps {
                script{
                    
                    TOKEN = sh (
                        script: '''
                            curl -X POST "https://domain/user/sign-in" -H "Content-Type: application/json" -d '{"email":"email@domain.com", "password":"xxxxxxxx", "remember": "false"}' | jq '.response.accessToken'
                        ''',
                        returnStdout: true
                    ).trim()
                    
                }
            }
        }
        
        stage('check status server1') {
            steps {
                script{ 
                    HTTP_CODE_GET = "200"
                    while(HTTP_CODE_GET == "200"){
                        
                        HTTP_CODE_POST = sh (
                            script: """
                                curl -X PATCH "http://server1ip/config/loadBalance/server1ip" -H "Content-Type: application/json" -H "authorization: Bearer $TOKEN" -o /dev/null -w "%{http_code}"
                            """,
                            returnStdout: true
                        ).trim()
                        
                        sleep 5
                        
                        HTTP_CODE_GET = sh (
                            script: '''
                                curl -o /dev/null -w "%{http_code}" "http://server1ip/config/isMaintenance"
                            ''',
                            returnStdout: true
                        ).trim()
                        
                        echo "${HTTP_CODE_GET} while"
                    }
                    
                    sleep 45
                        
                }
                echo "${HTTP_CODE_GET} break"
            }
        }
        
        stage('publish on ssh for server-1') {
            steps {
                sshPublisher(
                    publishers: 
                        [
                            sshPublisherDesc(
                                configName: '${Server1}', 
                                transfers: 
                                    [
                                        sshTransfer(
                                            cleanRemote: false, 
                                            excludes: '', 
                                            execCommand: '''
                                                            bash deploy.sh;
                                                        ''', 
                                            execTimeout: 120000, 
                                            flatten: false, 
                                            makeEmptyDirs: false, 
                                            noDefaultExcludes: false, 
                                            patternSeparator: '[, ]+', 
                                            remoteDirectory: '${remoteDir}', 
                                            remoteDirectorySDF: false, 
                                            removePrefix: 'build/libs', 
                                            sourceFiles: 'build/libs/deploy.jar'
                                        )
                                    ], 
                                usePromotionTimestamp: false, 
                                useWorkspaceInPromotion: false, 
                                verbose: true
                                )
                        ]
                    )
            }
        }
        
        stage('resotre status server1') {
            steps {
                script{ 
                    sleep 60
                    
                    while(HTTP_CODE_GET != "200"){
                        
                        HTTP_CODE_POST = sh (
                            script: """
                                curl -X PATCH "http://server1ip/config/loadBalance/server1ip" -H "Content-Type: application/json" -H "authorization: Bearer $TOKEN" -o /dev/null -w "%{http_code}"
                            """,
                            returnStdout: true
                        ).trim()
                        
                        sleep 5
                        
                        HTTP_CODE_GET = sh (
                            script: '''
                                curl -o /dev/null -w "%{http_code}" "http://server1ip/config/isMaintenance"
                            ''',
                            returnStdout: true
                        ).trim()
                        
                        echo "${HTTP_CODE_GET} while"
                    }
                    
                    
                }
            }
        }
        
        
        stage('check status server2') {
            steps {
                script{ 
                    HTTP_CODE_GET = "200"
                    while(HTTP_CODE_GET == "200"){
                        
                        HTTP_CODE_POST = sh (
                            script: """
                                curl -X PATCH "http://server2ip/config/loadBalance/server2ip" -H "Content-Type: application/json" -H "authorization: Bearer $TOKEN" -o /dev/null -w "%{http_code}"
                            """,
                            returnStdout: true
                        ).trim()
                        
                        sleep 5
                        
                        HTTP_CODE_GET = sh (
                            script: '''
                                curl -o /dev/null -w "%{http_code}" "http://server2ip/config/isMaintenance"
                            ''',
                            returnStdout: true
                        ).trim()
                        
                        echo "${HTTP_CODE_GET} while"
                    }
                    
                    sleep 45
                        
                }
                echo "${HTTP_CODE_GET} break"
            }
        }
        
        stage('publish on ssh for api-2') {
            steps {
                sshPublisher(
                    publishers: 
                        [
                            sshPublisherDesc(
                                configName: 'server2', 
                                transfers: 
                                    [
                                        sshTransfer(
                                            cleanRemote: false, 
                                            excludes: '', 
                                            execCommand: '''
                                                bash deploy.sh;
                                                ''', 
                                            execTimeout: 120000, 
                                            flatten: false, 
                                            makeEmptyDirs: false, 
                                            noDefaultExcludes: false, 
                                            patternSeparator: '[, ]+', 
                                            remoteDirectory: '${remoteDir}', 
                                            remoteDirectorySDF: false, 
                                            removePrefix: 'build/libs', 
                                            sourceFiles: 'build/libs/deploy.jar'
                                            )
                                    ], 
                                usePromotionTimestamp: false, 
                                useWorkspaceInPromotion: false, 
                                verbose: true
                            )
                        ]
                )
            }
        }
        
        stage('resotre status server2') {
            steps {
                script{ 
                    sleep 60
                    
                    while(HTTP_CODE_GET != "200"){
                        
                        HTTP_CODE_POST = sh (
                            script: """
                                curl -X PATCH "http://server2ip/config/loadBalance/server2ip" -H "Content-Type: application/json" -H "authorization: Bearer $TOKEN" -o /dev/null -w "%{http_code}"
                            """,
                            returnStdout: true
                        ).trim()
                        
                        sleep 5
                        
                        HTTP_CODE_GET = sh (
                            script: '''
                                curl -o /dev/null -w "%{http_code}" "http://server2ip/config/isMaintenance"
                            ''',
                            returnStdout: true
                        ).trim()
                        
                        echo "${HTTP_CODE_GET} while"
                    }
                    
                    
                }
            }
        }
    }
}

'서버 > 기타' 카테고리의 다른 글

[docker] 필요한거 한방에 조지기...  (0) 2022.02.17
[docker] 컨테이너에 접속하기  (0) 2022.02.17
Jenkins, Bitbucket(Git, private Repo)  (0) 2021.11.30
Linux Tomcat 설치 및 설정  (1) 2019.09.20

docker compose

 

version: '3.7'

services:
    mariadb:
        image: mariadb
        ports:
            - "3306:3306"
        volumes:
            - ./db/conf.d:/etc/mysql/conf.d
            - ./db/data:/var/lib/mysql
            - ./db/initdb.d:/docker-entrypoint-initdb.d
        environment:
            MYSQL_HOST: localhost
            MYSQL_ROOT_PASSWORD: rootpw
            MYSQL_ROOT_HOST: '%'
            TZ: Asia/Seoul
        networks:
            - default
        restart: always
        stdin_open: true
        tty: true
    redis:
        image: redis
        command: redis-server --requirepass redispw --port 6379
        container_name: redis6379
        hostname: redis6379
        labels:
            - "name=redis"
            - "mode=standalone"
        ports:
            - "6379:6379"
        networks:
            - default
        volumes:
            - ./redis:/data
        restart: always
        stdin_open: true
        tty: true
    rabbitmq:
        image: 'rabbitmq'
        container_name: rabbitmq-stream
        ports:
            - "5672:5672"
            - "15672:15672"
        networks:
            - default
        volumes:
            - ./rabbitmq/data:/var/lib/rabbitmq
            - ./rabbitmq/log:/var/log/rabbitmq
        environment:
            RABBITMQ_ERLANG_COOKIE: "RabbitMQ-My-Cookies"
            RABBITMQ_DEFAULT_USER: "admin"
            RABBITMQ_DEFAULT_PASS: "adminpw"
        restart: always
        stdin_open: true
        tty: true
    elasticsearch:
        container_name: elasticsearch
        image: elasticsearch:8.0.0
        ports:
            - "9200:9200"
            - "9300:9300"
        networks:
            - default
        volumes:
            - ./elasticsearch:/usr/share/elasticsearch/data
        environment:
            - ELASTIC_USERNAME=elastic
            - ELASTIC_PASSWORD=elasticpw
            - xpack.security.enabled=false
            - xpack.security.transport.ssl.enabled=false
            - http.cors.enabled=true
            - http.cors.allow-origin=*
            - discovery.type=single-node
            - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
            - TZ=Asia/Seoul
        restart: always
        privileged: true
        stdin_open: true
        tty: true
    kibana:
        container_name: kibana
        image: kibana:8.0.0
        ports:
            - "5601:5601"
        networks:
            - default
        environment:
            ELASTICSERCH_UTL: http://elasticsearch:9200
            ELASTICSEARCH_HOSTS: http://elasticsearch:9200
            TZ: Asia/Seoul
        restart: always
        privileged: true
        stdin_open: true
        tty: true

networks:
    default:
        external:
            name: local-env-network
# docker network create local-env-network

'서버 > 기타' 카테고리의 다른 글

[Jenkins] Pipeline을 활용한 배포  (1) 2023.01.31
[docker] 컨테이너에 접속하기  (0) 2022.02.17
Jenkins, Bitbucket(Git, private Repo)  (0) 2021.11.30
Linux Tomcat 설치 및 설정  (1) 2019.09.20
# 컨테이너ID 확인
$ docker ps

# 해당 컨테이너 bash 실행
docker exec -it -u root ${CONTAINER ID} /bin/bash

 

'서버 > 기타' 카테고리의 다른 글

[Jenkins] Pipeline을 활용한 배포  (1) 2023.01.31
[docker] 필요한거 한방에 조지기...  (0) 2022.02.17
Jenkins, Bitbucket(Git, private Repo)  (0) 2021.11.30
Linux Tomcat 설치 및 설정  (1) 2019.09.20

본래 Bitbucket의 Id/Pw를 사용해서 연동하려 했으나,

지속적으로 returned status code 128: 를 뱉음.

 

원인을 알 수 없는 와중에 구글링 해보니,

repository 생성시 private으로 생성한 경우 id/pw를 사용한 연결이 불가능 하다고...ㅠ

 

그래서 sshkeygen을 사용해서 쌍키 생성 후 

공개키는 bitbucket에 비밀키는 젠킨스 계정관리에 등록해줌

 

그리고 Git 접속 경로는 https가 아닌 ssh 접속

'서버 > 기타' 카테고리의 다른 글

[Jenkins] Pipeline을 활용한 배포  (1) 2023.01.31
[docker] 필요한거 한방에 조지기...  (0) 2022.02.17
[docker] 컨테이너에 접속하기  (0) 2022.02.17
Linux Tomcat 설치 및 설정  (1) 2019.09.20

매번 하는 작업인데 항상 중간부분을 까먹어서 헤매다 보니, 정리를 좀 해두는게 좋겠다 싶어서..

 

톰캣은 일단 tar.gz 파일을 받고,

 

폴더 구조는 app 과 web 으로 구분을 짓는다.

 

app 아래에 여러 톰캣을 넣어놓고, web아래는 webapps를 옮겨서 해당 서비스 이름으로 변경한다.

 

톰캣/conf/server.xml 의 docBase를 확인해보면 webapps로 되어 있을텐데,

이걸 나는 web 아래로 복사해서 서비스명으로 변경하였기 때문에,

 

docBase="/web/서비스명/"으로 해준다.

 

이렇게 구조를 나누는 이유는...전에 SE 한분을 일한적이 있는데 이렇게 하는게 깔끔하다고 해서...ㅎㅎ

 

그리고 ci에서 배포를 하기 위해 tomcat-users.xml 또한 설정 한다.

 

'

설정이 제대로 안되었을 경우 매니저 접속시 이런 페이지를 만날 수 있다.

 

manager-* 각 롤을 마다 역할이 다르며, ci에서 이용하기 위한 롤은 script다.

 

여기까지는 늘상 알고 있고 딱히 헷갈릴것도 없는데...

 

항상 이부분이 문제

딱히 문제랄건 없고, 꼭 이 페이지를 만나야 기억이 난다 ㅠㅠ

 

manager/META-INF/context.xml 을 확인해보면

<Context> 태그 아래에 기본적으로 두개의 밸브가 있다.

이 설정은 외부에서 톰캣 매니저로의 접속을 막는 설정이며,

해당 설정을 주석처리 해주거나, ip를 정확히 지정해주면 외부에서 매니저로 접속이 가능하다.

 

운영환경에서 보통 톰캣과 ci를 같은서버에 두지 않기에, 이정도 설정을 알아놓으면 아주 유용할듯.

 

그럼 오늘도 고생하세유.

+ Recent posts