해당 글은 Notion에서 작성되어진 글 입니다.

https://hyeon0j0.notion.site/Swagger-6506f70d58ba46a79f8841a9e413b7bf

 

Swagger 사용법 그리고 커스터마이징

🗒️ 노트 주제

hyeon0j0.notion.site

🗒️ 노트 주제


  • Swagger란 무엇인가??
  • Swagger 사용방법
  • Swagger 커스터마이징 하는 방법

🗝️ 핵심


Swagger란 무엇인가?


서버는 클라이언트와 통신을 하기 위해서 인터페이스 문서를 작성을 하고, 이를 공유하면서 API 규격을 맞춰 나간다.

기존에 팀에서는 Excel을 공유하여 문서로 관리하고, 테스트는 Postman을 통해서 테스트하고 클라이언트에게 테스트 방법을 안내할 때에는 Postman의 Export 기능을 통해 JSON파일로 테스트 명세를 전달하였다.

그러나 Swagger의 도입으로 인해 서버가 정상 기동만 되어있으면 웹상에서 바로 확인 및 테스트가 가능하게 제공할 수 있다.

그리고 Swagger에서 제공하는 api-docs의 JSON 파일을 이용하면 클라이언트 측에서는 Swagger Build를 통해 객체 생성 및 호출 함수까지 자동으로 완성시켜주어 개발 속도가 향상된다.

그럼 Swagger란 정확하게 무엇인가?

Swagger 는 REST API를 설계, 구축, 문서화 및 사용하는 데 도움이 될 수 있는 OpenAPI 사양을 기반으로 구축된 오픈 소스 도구 세트입니다.

About Swagger Specification | Documentation | Swagger

기존의 명칭은 springfox swagger 라는 명칭으로 되어 있다가, 어느부터 springdoc-openapi로 변경이 되었고, springfox swagger의 경우에는 특정 버전만 springboot에서 정상 동작하는 오류가 있었는데 springdoc-openapi로 변경됨에 따라서는 호환성 이슈는 사라진 것 같다. 프로세스가 실행중일때 excute 버튼이 비활성화 되는 기능도 추가됨

Swagger가 제공해주는 도구 중에서 Swagger-ui 툴을 통해서 웹상에서 표출하는 방법에 대해서 작성해보겠다.

Swagger 사용 방법


Swagger의 사용방법은 Java Spring Boot + Gradle을 기준으로 설명하겠다.

    1. Gradle 설정

Swagger-ui 버전정보는 확인을 통해 설정 할 것

  1.  
  2. implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-web:2.7.0' testImplementation 'org.springframework.boot:spring-boot-starter-test' /* SWAGGER */ implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.9'
  3. API 설명 작성
    • 애노테이션 방법
    • @OpenAPIDefinition(info = @Info(title = "Hustar API 명세서", description = "API 명세서", version = "v1", contact = @Contact(name = "taehyeonkim", email = "taehyeonkim@kakao.com") ) )
    • Java Config 파일 방법

두가지중 한가지 방법으로 선택

  •  
  • @Configuration public class SwaggerConfig { @Bean public OpenAPI openAPI() { Info info = new Info().title("Hustar API 명세서").version("v1") .description("API 명세서") .contact(new Contact().name("taehyeonkim").email("taehyeonkim@kakao.com")) .license(new License().name("Apache License Version 2.0").url("http://www.apache.org/licenses/LICENSE-2.0.html")); return new OpenAPI() .components(new Components()) .info(info); } }
    1. Controller, Vo 에 설명 작성
       @Getter
       @Setter
       @ToString
       public class TestParmVo {
           @Schema(description = "이름", example = "김태현")
           String name;
      
           @Schema(description = "인사말", example = "안녕하세요")
           String message;
       }

Swagger Annotaion 추가 설명은 공식 wiki에서 확인

    1.  

Annotations · swagger-api/swagger-core Wiki

  1.  
  2. // Controller @RestController public class TestController { @Operation(summary = "이름을 출력하는 Controller", description = "입력 파라미터 이름 출력") @PostMapping("/test") public TestResultVo test(@RequestBody TestParmVo testParmVo){ return TestResultVo.builder() .result(testParmVo.getName()) .build(); } @Operation(summary = "메세지를 출력하는 Controller", description = "입력 파라미터 메세지 출력") @PostMapping("/test2") public TestResultVo test2(@RequestBody TestParmVo testParmVo){ return TestResultVo.builder() .result(testParmVo.getMessage()) .build(); } }
  3. 로컬 서버 기동 후 localhost:8080/swagger-ui.html 접속
  4. 스크린샷 2022-07-02 시간: 10.44.51.png
  5. 확인설명 작성한 부분 위치결과 확인
  6. 결과 확인
  7. 설명 작성한 부분 위치

Swagger 커스터마이징


OpenAPI이므로 Swagger에 로고도 바꾸고 색상도 바꾸고 사용자의 입맛에 바꿀수가 있는데 그중 로고와 헤더 색상 바꾸는 것만 설명을 하고자 한다.

  • GIt Issue에 있는 css path를 통한 커스터마이징

https://github.com/springdoc/springdoc-openapi/issues/737

해당 방식으로 하게 되면 Swagger Path에 해당 Controller를 예외 처리 해줘야 되며, 내가 바꾸고 싶은 부분 마다 Endpoint를 만드는 느낌이라 개인적으로는 비추

  • Swagger UI Resource를 통한 직접 커스터마이징
  1. swagger-ui resource 다운또는 Gradle에서 Import된 Resource를 사용
  2. Untitled
  3. https://github.com/swagger-api/swagger-ui 에서 dist 폴더 다운
  1. 인터넷 탭 아이콘 , 이름 변경
  2. <!-- index.html --> <!-- HTML for static distribution bundle build --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> **<!-- 해당 부분 이름 변경 --> <title>Hustar Swagger UI</title> <!-- 해당 부분 이름 변경 끝 -->** <link rel="stylesheet" type="text/css" href="./swagger-ui.css" /> <link rel="stylesheet" type="text/css" href="index.css" /> **<!-- 해당 부분 아이콘 리소스 변경 --> <link rel="icon" type="image/png" href="./hustar_32x32.png" sizes="32x32" /> <link rel="icon" type="image/png" href="./hustar_32x32.png" sizes="16x16" /> <!-- 해당 부분 아이콘 리소스 변경 끝 -->** </head> <body> <div id="swagger-ui"></div> <script src="./swagger-ui-bundle.js" charset="UTF-8"> </script> <script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script> <script src="./swagger-initializer.js" charset="UTF-8"> </script> </body> </html>
  1. Swagger-ui 왼쪽 상단 로고 변경
    1. 적당한 이미지 로고(배경이 없는 png 파일 추천) 준비해서 Resource폴더 안에 넣어놓기
    2. Untitled
    3. swagger-ui-standalone-preset.js 수정 (배너 이미지 변경)
       // 변경
      
       return p.createElement("div", {className: "topbar"}, p.createElement("div", {className: "wrapper"}, p.createElement("div", {className: "topbar-wrapper"}, p.createElement(o, null, p.createElement("img", {
                                   height: "40",
                                   // TODO :: 바꿈
                                   src: "./Hustar.png",
                                   // TODO :: 바꿈
                                   alt: "Hustar - Swagger UI"
                               })), p.createElement("form", {
                                   className: "download-url-wrapper",
                                   onSubmit: f
                               }, b()(c).call(c, (function (t, e) {
                                   return (0, p.cloneElement)(t, {key: e})
                               }))))))
    4. // 기존 return p.createElement("div", {className: "topbar"}, p.createElement("div", {className: "wrapper"}, p.createElement("div", {className: "topbar-wrapper"}, p.createElement(o, null, p.createElement("img", { height: "40", src: j, alt: "Swagger UI" })), p.createElement("form", { className: "download-url-wrapper", onSubmit: f }, b()(c).call(c, (function (t, e) { return (0, p.cloneElement)(t, {key: e}) }))))))
4. 상단 배너 Back-ground 색상 변경

Index.css 파일 수정

```css
/** index.css **/

.swagger-ui .topbar {
    background-color: lightgray;
}
```

1. 결과 확인

    ![Untitled](Swagger%20%E1%84%89%E1%85%A1%E1%84%8B%E1%85%AD%E1%86%BC%E1%84%87%E1%85%A5%E1%86%B8%20%E1%84%80%E1%85%B3%E1%84%85%E1%85%B5%E1%84%80%E1%85%A9%20%E1%84%8F%E1%85%A5%E1%84%89%E1%85%B3%E1%84%90%E1%85%A5%E1%84%86%E1%85%A1%E1%84%8B%E1%85%B5%E1%84%8C%E1%85%B5%E1%86%BC%20839b56b3485a41b489336dd45b2c9321/Untitled%202.png)

 

소스코드

https://github.com/taehyeon3549/SwaggerCustomizing

 

GitHub - taehyeon3549/SwaggerCustomizing: Swagger 문서를 개인의 입맛에 맞게 수정 변경

Swagger 문서를 개인의 입맛에 맞게 수정 변경. Contribute to taehyeon3549/SwaggerCustomizing development by creating an account on GitHub.

github.com

 

🔗 참고 노트


Custom RestTemplateBuilder

  1. Builder 패턴을 활용한 RestTemplateBuilder
  2. Spring의 IoC를 활용한 싱글톤 RestTemplate
  3. RestTemplate의 Customizing
  4. RestTemplateBuilder 상속을 통한 기능 확장
[ 구조 ] 

TaehyeonRestTemple = RestTemplateBuilder + Taehyeon's Function    // Builder-pattern
                              |
                              |- HttpClient
                              |     ㄴ Connection Pool
                              |- HttpComponentsClientHttpRequestFactory
                              |     ㄴ Time Out
                              ㄴ CustomRestTemplateCustomizer
                                    ㄴ Logging                                    

[클래스 구조] TaehyeonRestTemplateBuilder 구조

Example

@Autowired
private TaehyeonRestTempleBuilder taehyeonRestTempleBuilder;


/** GET 요청 예시(String return) **/
String result = taehyeonRestTempleBuilder
                .requestUriAndPath(DATA_BASE_URL
                        , "/VilageFcstInfoService_2.0/getVilageFcst"
                        , new LinkedMultiValueMap<>() {{
                            add("serviceKey", SERVICE_KEY);
                            add("pageNo", "1");
                            add("dataType", "JSON");
                            add("base_date", "20220207");
                            add("base_time", "1200");
                            add("nx", "57");
                            add("ny", "127");
                        }})
                .getForObject();

/** GET 요청 예시 **/
ResponseEntity<Object> result = taehyeonRestTempleBuilder
                .headers(new HashMap<>(){
                    {
                        put("X-Auth-Token", authKey);
                    }
                })
                .requestUriAndPath(crowdworksDefaultUrl
                        , "/project/output"
                        , new LinkedMultiValueMap<>() {{
                            add("queryingField", "");
                            add("queryingWord", "");
                            add("dataStatus", "");
                            add("edited", "");
                            add("rangingField", "");
                            add("page", String.valueOf(page));
                        }})
                .get();


/** POST 요청 예시 **/
ResponseEntity<Object> result = taehyeonRestTempleBuilder
                .contentType(MediaType.APPLICATION_JSON)
                .body(loginInfo)
                .requestUriAndPath(apiUrl, loginpath, null)
                .post();


/** PATCH 요청 예시 **/
ResponseEntity<Object> result = taehyeonRestTempleBuilder
                .headers(new HashMap<>(){{
                    put("X-Auth-Token", authKey);
                }})
                .requestUriAndPath(apiUrl, authPath, null)
                .patch();

개발 목표

  • 비즈니스 로직에서 구현하던 RestTemplate 생성과 처리 부분을 분리
  • 추후 연계 시스템 개발에서도 해당 모듈을 사용하여 단순히 호출만을 통한 처리를 할 수 있게끔 개발
  • Spring과 디자인 패턴을 공부하고 있는 것을 복습하며 실적용을 노림
  • RestTemplate의 ConnectionPool 설정을 통해 3-Hankshake의 지연을 줄임
    (연계 서버이므로 API 호출 서버가 keep-alive 상태임을 가정 )
  • 기존의 Resttemplate 과 Custom한 TaehyeonRestTemplate을 공존하여 Client의 선택에 따라 사용할 수 있도록 개발
  • jar 라이브러리화 하여 추후 연계 서버 개발시 개발 시간을 단축
  • 회사 연계 공통 모듈로 사용할 수 있게??? :D


[개발 Note]

  • 2022-02-22

    • 프로젝트 Init
    • Builder patter 초기 동작 코드 작성
    • Get 요청시의 parameter를 명시적으로 주입하기 위해 MultiValueMap 과 UriComponentsBuilder를 활용하여 요청 URI를 생성
    • 모듈 자체 Exception 생성 (수정 보완필요)
  • 2022-02-23

    • RestTemplate이 Connection Pool이 없이 요청할때마다 3-HandShack를 진행한다는 것을 공부, 이에 따라 Connection Pool을 설정하여 오버헤드를 줄임
    • application.properties 를 통한 Connection Pool과 TimeOut 설정을 할 수 있게 설정
    • 초기의 TaehyeonRestTemplateBuilder의 코드에 Connection Pool과 TimeOut 설정을 하여 Bean 생성을 하려고 하였으나 ' RestTemplateBuilder를 사용한 RestTemplate 설정 방법 : https://www.baeldung.com/spring-rest-template-builder ' 을 보고 Customizing Logging을 추가 및 각 기능을 분리 시킨 Bean으로 생성하여 주입되어 Application Context가 자동 관리 되도록 함
    • RestTempleBuilder의 생성자에 CustomRestTemplateCustomizer가 parm으로 주입되는데 이에 따른 TaehyeonRestTemplateBuilder를 RestTemplateBuilder를 상속 받아 기능을 확장 시키는 방향으로 전환
    • (중요!!) 상속받은 Builder를 통한 build를 시키면 return이 super의 RestTemplate 이고, sub의 TaehyeonRestTempleBuilder로 casting이 안됨.
      해당 문제는 Builder 형태로 생성하고 마지막에 Casting을 하는 것이 아닌, Casting 한 Builder를 생성하고 생성한 객체에서 추가적인 작업을 진행
      (때문에 알고있던 Upcasting과 DownCasting 다시 공부....)
    • 새롭게 만들어낸 TaehyeonRestTemplate과 기존의 RestTemplate을 공용으로 사용할 수 있도록 2가지 type의 Bean 생성하는 방향으로 생각중
    • 테스트 코드 추가
  • 2022-02-25

    • Default RestTemplate Bean 추가 하여 Client가 선택적으로 사용할 수 있게 수정
    • TestCode에 기존 방식과 TaehyeonRestTemplate 방식 비교 코드 추가


[개발 이슈]

  1. RestTemplate Get 요청시 String 으로 parameter를 주입시 자동 Encoding 처리 되어 요청 [해결]

parmeter 를 URI로 주입하여 Encoding 되지 않게 처리

restTemplate.getForObject(new URI(URLDecoder.decode(requestUri.toString(), "UTF-8")), String.class);
  1. 상속받은 Builder를 통한 build를 시키면 return이 super의 RestTemplate 이고, sub의 TaehyeonRestTempleBuilder로 casting이 안됨 [해결]

Casting 한 Builder를 생성하고 생성한 객체에서 추가적인 작업을 진행

//불가능
TaehyeonRestTempleBuilder taehyeonRestTempleBuilder = (TaehyeonRestTempleBuilder)new TaehyeonRestTempleBuilder(customRestTemplateCustomizer())
        .requestFactory(() -> new BufferingClientHttpRequestFactory(factory))
        .additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")));

// 가능
TaehyeonRestTempleBuilder taehyeonRestTempleBuilder = new TaehyeonRestTempleBuilder(customRestTemplateCustomizer());

taehyeonRestTempleBuilder.requestFactory(() -> new BufferingClientHttpRequestFactory(factory))
        .additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")));
  1. TaehyeonRestTempleBuilder 는 Builder인가 RestTemplate 인가.....?

  2. RestTemple를 통해 Get 요청시 MessageConverter 오류**[해결]**

  • TaehyeonRestTemplateBuilder은 "additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")));" 만으로 Response Message Converting이 정상 이루어 졌지만, 기본 RestTemplateBuilder에도 똑같이 하였으나 Converting 오류 발생

혹시 몰라 TaehyeonRestTemplate 에도 MessageCoverter 설정 추가

// 오류 메세지
org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class java.lang.Object] and content type [application/json;charset=UTF-8]

// 해결 코드

RestTemplate restTemplate1 =restTemplateBuilder
.additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")))
.build(); // restemplate 생성

List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));  //converter 설정
messageConverters.add(converter);  

restTemplate1.setMessageConverters(messageConverters);   // messageConverter 직접 추가

 

* 원문과 예제 코드는 Git에 있습니다.

https://github.com/taehyeon3549/RestTemplateBuilder

 

GitHub - taehyeon3549/RestTemplateBuilder: Builder 패턴을 활용한 RestTemplateBuilder

Builder 패턴을 활용한 RestTemplateBuilder. Contribute to taehyeon3549/RestTemplateBuilder development by creating an account on GitHub.

github.com

 

RabbitMq

수정일 수정 내용 수정자
2022. 04. 13 최초 작성 cs 박영희
2022. 04. 15 설치 가이드 추가 cs 김태현


설치 가이드

환경 설치 버전
OS CentOS Linux release 7.9.2009 (Core)
RabbitMq 3.8.28
Erlang 24.2.1
Others OpenSSL 1.1

RabbitMq는 Erlang과 호환성이 중요

호환성 확인 : https://www.rabbitmq.com/which-erlang.html

Erlang 24를 CentOS7에서 사용하기 위해선 OpenSSL1.1로 upgrade 필요

공식 문서: Older distributions can also lack a recent enough version of OpenSSL. Erlang 24 cannot be used on distributions that do not provide OpenSSL 1.1 as a system library. CentOS 7 and Fedora releases older than 26 are examples of such distributions.

이전 배포판에는 충분히 최신 버전의 OpenSSL이 없을 수도 있습니다. 시스템 라이브러리로 OpenSSL 1.1을 제공하지 않는 배포판에서는 Erlang 24를 사용할 수 없습니다. CentOS 7과 26보다 오래된 Fedora 릴리스가 그러한 배포판의 예입니다.

  • 설치 링크

    Erlang : https://www.erlang.org/patches/otp-23.3.4.13

    RabbitMq : https://packagecloud.io/rabbitmq/rabbitmq-server/

  • 설치

    • OpenSSL 1.1 설치
      # OpenSSL 버전 확인 
      # centos7 에선 OpenSSL 1.0.2k-fips  26 Jan 2017 표출
      $ openssl version
      
      # TLS 지원 버전 확인
      # centos7 에선 SSLv3, TLSv1.2 2개만 표출
      $ openssl ciphers -v | awk '{print $2}' | sort | uniq
      
      # 기존 openssl 삭제
      $ yum remove openssl
      
      # 패키지 설치
      $ yum install -y gcc gcc-c++ pcre-devel zlib-devel perl wget
      
      # tar 다운
      $ wget https://www.openssl.org/source/openssl-1.1.1m.tar.gz
      
      # tar 압축 해제
      $ tar -xvf openssl-1.1.1m.tar.gz
      
      # 이동
      $ cd openssl-1.1.1m
      
      # make를 하기 위해 config 실행
      $ ./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl shared zlib
      
      # make
      $ make & make install
      
      # 해당 파일에 openssl 경로 입력
      $ vi /etc/ld.so.conf.d/openssl-1.1.1k.conf
      
      # 파일안에 ssl 컴파일 경로 기재
      /usr/local/ssl/lib
      
      # lib64에 심볼 링크 생성
      $ ln -s /usr/local/ssl/lib/libssl.so.1.1 /usr/lib64/libssl.so.1.1
      $ ln -s /usr/local/ssl/lib/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1
      $ ln -s /usr/local/ssl/bin/openssl /bin/openssl
      
      # 설치 이후 버전 및 TLS 지원 확인        
      $ openssl version
      #OpenSSL 1.1.1m  14 Dec 2021
      
      $ openssl ciphers -v | awk '{print $2}' | sort | uniq
      #SSLv3
      #TLSv1
      #TLSv1.2
      #TLSv1.3        
      
    • Erlang 설치
      # EPEL 저장소 추가
      $ yum install epel-release
      
      # erlang 설치를 위한 npm 다운
      $ wget http://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
      
      # rpm 실행(repo 추가)
      $ rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
      
      # erlang 설치
      $ yum install erlang
      
      # erlang 버전 확인
      $ cat /usr/lib64/erlang/releases/RELEASES
      
    • RabbitMq 설치
      # socat 설치
      sudo yum install socat
      
      # npm 다운
      $ wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.28/rabbitmq-server-3.8.28-1.el8.noarch.rpm
      
      #Signing Keys 추가
      $ rpm --import https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc
      
      # 설치            
      rpm -Uvh https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.28/rabbitmq-server-3.8.28-1.el8.noarch.rpm
      


플러그인 활성화

#관리자페이지 
$ rabbitmq-plugins enable rabbitmq_management

# 관리자에이전트 
$ rabbitmq-plugins enable rabbitmq_management_agent

# MQTT 
$ rabbitmq-plugins enable rabbitmq_mqtt


포트오픈

참고 : https://docs.vmware.com/en/VMware-Tanzu-RabbitMQ-for-Kubernetes/1.2/tanzu-rmq/GUID-networking.html#ports

  • 설정(firewall-cmd)

    # empd
    $ firewall-cmd --permanent --zone=public --add-port=4369/tcp
    
    # TLS가 있거나 없는 AMQP 0-9-1 및 AMQP 1.0 클라이언트에서 사용
    $ firewall-cmd --permanent --zone=public --add-port=5671/tcp    
    $ firewall-cmd --permanent --zone=public --add-port=5672/tcp
    
    # TLS가 있거나 없는 RabbitMQ Stream 프로토콜 클라이언트 에서 사용
    $ firewall-cmd --permanent --zone=public --add-port=5551/tcp    
    $ firewall-cmd --permanent --zone=public --add-port=5552/tcp
    
    # Erlang 분산(inter-node와 cli 통신을 위한 사용 (rabbitmqctl))
    # 노드 간 및 CLI 도구 통신(Erlang 배포 서버 포트)에 사용되며 동적 범위에서 할당
    $ firewall-cmd --permanent --zone=public --add-port=25672/tcp
    
    # 관리 플러그인을 사용할때(http api , management UI)(optional)
    $ firewall-cmd --permanent --zone=public --add-port=15672/tcp
    
    # STOMP 클라이언트 (optional)
    $ firewall-cmd --permanent --zone=public --add-port=61613/tcp
    $ firewall-cmd --permanent --zone=public --add-port=61614/tcp
    
    # MQTT 클라이언트 (optional)
    $ firewall-cmd --permanent --zone=public --add-port=1883/tcp
    $ firewall-cmd --permanent --zone=public --add-port=8883/tcp
    
    # ???
    $ firewall-cmd --permanent --zone=public --add-port=35197/tcp
    
  • 설정(iptables)

    $ iptables -I INPUT -m tcp -p tcp --dport 35197 -j ACCEPT
    # 등등등....
    
  • 적용

    $ firewall-cmd --reload
    
  • 확인

    $ firewall-cmd –-list-all
    


기본설정

  • rabbitmq-server 실행

    $ systemctl start rabbitmq-server
    
  • ravvitmq-server 상태

    $ systemctl status rabbitmq-server
    
  • rabbitmq 상태 확인

    $ rabbitmq-diagnostics status
    
  • rabbitmq 로그 확인

    $ cat /var/log/rabbitmq/~~~.log
    


노드명 변경

노드명은 시스템 user, host 명과 중복이 되지 않게 설정 할 것!!! 클러스터링 묶을때 slave mq가 연결할 때 혼동이 생겨 연결이 안됨.

참고 : https://sleeplessbeastie.eu/2020/02/03/how-to-specify-rabbitmq-node-name/

  • 기존 파일 삭제(Optional)
    $ rm -rf /var/lib/rabbitmq/mnesia/*
    
  • 환경 변수 파일 생성

    파일명 조심할것!! ==> .config, .conf

    • rabbitmq.config

      # vi /etc/rabbitmq/rabbitmq.config
      # 뒤에 마침표(.) 필히 찍어 줄것
      [
          {mnesia,
              [
              {dump_log_write_threshold, 1000},
              {dc_dump_limit, 40}
              ]
          },
          {rabbit,
              [
              {tcp_listeners, [5672]},
              {vm_memory_high_watermark, 0.4}
              ]
          },
          {rabbitmq_tracing,
              [
              {username, "wini"}
              ]
          }
      ].
      
    • rabbitmq-env.config

      꼭!!!! nodename에 node이름@호스트명 을 필기 작성해줄 것

      # vi /etc/rabbitmq/rabbitmq-env.config    
      # Defaults to rabbit. This can be useful if you want to run more than one node
      # per machine - RABBITMQ_NODENAME should be unique per erlang-node-and-machine
      # combination. See the clustering on a single machine guide for details:
      # http://www.rabbitmq.com/clustering.html#single-machine
      NODENAME=wini1@rabbit1
      # By default RabbitMQ will bind to all interfaces, on IPv4 and IPv6 if
      # available. Set this if you only want to bind to one network interface or#
      # address family.
      #NODE_IP_ADDRESS=127.0.0.1
      # Defaults to 5672.
      #NODE_PORT=5672
      #USE_LONGNAME=true
      
  • node 표현 확인
    $ rabbitmqctl eval "node()."
    
    #[root@localhost rabbitmq]# rabbitmqctl eval "node()."
    #wini2@rabbit2
    


계정

  • 계정조회 : rabbitmqctl list_users
  • 계정등록 : rabbitmqctl add_user 계정명 비밀번호
  • 권한부여 : rabbitmqctl set_user_tags 계정명 administrator
  • 계정 할당 권한 부여 : rabbitmqctl set_permissions -p / wini "." "." ".*"


도메인적용

  1. vi /etc/hosts 추가
  2. hostnamectl set-hostname myhost


클러스터링

공식 : https://www.rabbitmq.com/clustering.html

참고 : https://intrepidgeeks.com/tutorial/rabbitmq-cluster-and-load-balancing-construction

rabbitmqctl reset 하면 userlist가 초기화 되니 재설정 해줄것

  • 클러스터 구성할 서버들 host 설정

    # vi /etc/hosts
    
    172.18.220.160 rabbit1
    172.18.222.136 rabbit2
    
  • 클러스터 구성 포트 허용 확인

    # 클러스터 노드 찾는 port
    $ firewall-cmd --permanent --zone=public --add-port=4369/tcp    
    
    # TLS가 있거나 없는 AMQP 0-9-1 및 AMQP 1.0 클라이언트에서 사용
    $ firewall-cmd --permanent --zone=public --add-port=5671/tcp    
    $ firewall-cmd --permanent --zone=public --add-port=5672/tcp
    
    # inter-node 와 cli 통신을 위한 사용 (rabbitmqctl)
    $ firewall-cmd --permanent --zone=public --add-port=25672/tcp
    
    # http api, management UI
    $ firewall-cmd --permanent --zone=public --add-port=15672/tcp    
    
    # 적용    
    $ firewall-cmd --reload
    
    # 확인    
    $ firewall-cmd –-list-all
    
  • Erlang 쿠키 맞추기

    • master 에 있는 /var/lib/rabbitmq/.erlang.cookie 를 slave로 옮겨줌

      기존 파일 권한을 777로 준 다음 다시 400으로 세팅할 것

          $ scp /var/lib/rabbitmq/.erlang.cookie wini@rabbit2:/var/lib/rabbitmq/
      
  • rabbitmq 클러스터 설정

    설정은 slave -> master 로만 설정

    # 노드 중지
    $ rabbitmqctl stop_app --
    
    # 노드 다시 세팅
    $ rabbitmqctl reset
    
    # 클러스터 조인
    # slave->master
    $ rabbitmqctl join_cluster wini1@rabbit1
    
    # 각 rabbitmq 시작
    $ rabbitmqctl start_app
    
    # 각 rabbitmq 상태 확인
    $ rabbitmqctl cluster_status
    
  • rabbitmq 클러스터 성공 결과

    # rabbitmqctl cluster_status
    
    Cluster status of node wini2@rabbit2 ...
    Basics
    
    Cluster name: wini1@rabbit2
    
    Disk Nodes
    
    wini1@rabbit1
    wini2@rabbit2
    
    Running Nodes
    
    wini1@rabbit1
    wini2@rabbit2
    
    Versions
    
    wini1@rabbit1: RabbitMQ 3.8.28 on Erlang 24.2.1
    wini2@rabbit2: RabbitMQ 3.8.28 on Erlang 24.2.1
    
    Maintenance status
    
    Node: wini1@rabbit1, status: not under maintenance
    Node: wini2@rabbit2, status: not under maintenance
    
    Alarms
    
    (none)
    
    Network Partitions
    
    (none)
    
    Listeners
    
    Node: wini1@rabbit1, interface: [::], port: 15672, protocol: http, purpose: HTTP API
    Node: wini1@rabbit1, interface: [::], port: 1883, protocol: mqtt, purpose: MQTT
    Node: wini1@rabbit1, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
    Node: wini1@rabbit1, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
    Node: wini2@rabbit2, interface: [::], port: 15672, protocol: http, purpose: HTTP API
    Node: wini2@rabbit2, interface: [::], port: 1883, protocol: mqtt, purpose: MQTT
    Node: wini2@rabbit2, interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
    Node: wini2@rabbit2, interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
    
    Feature flags
    
    Flag: drop_unroutable_metric, state: enabled
    Flag: empty_basic_get_metric, state: enabled
    Flag: implicit_default_bindings, state: enabled
    Flag: maintenance_mode_status, state: enabled
    Flag: quorum_queue, state: enabled
    Flag: user_limits, state: enabled
    Flag: virtual_host_metadata, state: enabled
    

    클러스터링 성공 결과



MQTT 적용

  1. exchange : amq.topic
  2. routingKey : 슬러쉬(/) 대신 점(.) 으로 표기
# /usr/local/etc/rabbitmq/etc/rabbitmq/rabbitmq.conf

mqtt.listeners.tcp.default = 1883
## Default MQTT with TLS port is 8883
# mqtt.listeners.ssl.default = 8883

# anonymous connections, if allowed, will use the default
# credentials specified here
mqtt.allow_anonymous  = true
mqtt.default_user     = guest
mqtt.default_pass     = guest

mqtt.vhost            = /
mqtt.exchange         = amq.topic
# 24 hours by default
mqtt.subscription_ttl = 86400000
mqtt.prefetch         = 10
mqtt.subscription_ttl = undefined

 

 

** 원문과 스크립트는 Git에 있습니다.

https://github.com/taehyeon3549/StudyAllOfThings/tree/master/RabbitMq

 

GitHub - taehyeon3549/StudyAllOfThings: RabbitMQ

RabbitMQ 정리

github.com

'머리 뜯으며 개발 > MQ' 카테고리의 다른 글

MQTT] 정리 잘되어 있는 링크 정리  (0) 2020.07.06

ELK (Elasticksearch + Logstash + Kibana)

수정일 수정 내용 수정자
2022. 03. 31 최초 작성 cs 김태현


시스템 목표

  • 기존 scouter 모니터링 Tool은 Window 기반의 응용이므로 환경 제약이 존재
  • 공통 환경인 Web 기반의 로그 확인을 위함
  • 부가적으로 Rest호출 방식을 통한 추가적인 서비스 가능 (확장성)


기존 scouter 시스템 구성

title



ELK 시스템 구성

title

title



설치 요구사항

[ 참고 url ] https://www.elastic.co/guide/kr/elasticsearch/reference/current/gs-installation.html

Java 8 이상 (Java 11 추천)



설치 가이드


1. jdk 설정:

  • JAVA_HOME 설정

    # vi /etc/profile
    
    export JAVA_HOME=/elk/jdk/zulu11.54.25-ca-jdk11.0.14.1-linux_x64
    export PATH=$JAVA_HOME/bin:$PATH
    export JAVA_OPTS=Dfile.encoding=UTF-8
    export CLASSPATH="."
    
  • 적용

    $ source /etc/profile 
    
  • ssh 재접속

  • 설치확인

    $ echo $JAVA_HOME
    
  • 설치 버전 확인

    $ java -version
    

2. Elasticsearch + Kibana 설치 :

설치 경로 : https://www.elastic.co/kr/start

설치 형태 : https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html

  • 기본 옵션 및 필수 속성 설정:

    # vi /usr/local/elasticsearch/config/elasticsearch.yml
    
    
    # ---------------------------------- Cluster --------------------------------
    #
    cluster.name: wini  
    #
    # ------------------------------------ Node ---------------------------------
    #
    node.name: node_master
    #
    # ----------------------------------- Paths ---------------------------------
    #
    path.data: /elk/elasticsearch/elasticsearch/data
    path.logs: /elk/elasticsearch/elasticsearch/logs
    #
    # ----------------------------------- Memory --------------------------------
    #
    bootstrap.memory_lock: true
    #
    # ---------------------------------- Network --------------------------------
    #
    network.host: 0.0.0.0
    http.port: 9200
    
    # --------------------------------- Discovery -------------------------------
    discovery.seed_hosts: ["0.0.0.0"]
    cluster.initial_master_nodes: ["node_master"]
    
    # ---------------------------------- Various -------------------------------
    action.auto_create_index: .monitoring*,.watches,.triggered_watches,.watcher-history*,.ml*
    
    cluster.initial_master_nodes: ["node_master"]
    #
    # --------------------------------- Discovery -------------------------------
    
    # filebeat- 로 시작하는 인덱스는 자동 인덱스 생성 활성화 설정
    action.auto_create_index: filebeat-*
    
    #----------------------- BEGIN SECURITY AUTO CONFIGURATION ------------------
    
    # Enable security features
    xpack.security.enabled: false
    
    xpack.security.enrollment.enabled: false
    
    #----------------------- END SECURITY AUTO CONFIGURATION --------------------
    
  • elasticsearch 데이터 확인

    $ curl -X GET http://localhost:9200/classes?pretty
    
    
      # [wini@localhost kibana]$ curl -X GET http://localhost:9200/classes?pretty
      # {
      #   "error" : {
      #     "root_cause" : [
      #       {
      #         "type" : "index_not_found_exception",
      #         "reason" : "no such index [classes]",
      #         "resource.type" : "index_or_alias",
      #         "resource.id" : "classes",
      #         "index_uuid" : "_na_",
      #         "index" : "classes"
      #       }
      #     ],
      #     "type" : "index_not_found_exception",
      #     "reason" : "no such index [classes]",
      #     "resource.type" : "index_or_alias",
      #     "resource.id" : "classes",
      #     "index_uuid" : "_na_",
      #     "index" : "classes"
      #   },
      #   "status" : 404
      # }
    

3. Logstash 설치

설치 경로 : https://www.elastic.co/kr/downloads/logstash

  • 설치 테스트
    • 테스트 conf 추가

      # vi /elk/logstash/logstash/config/test.conf
      
      input{
              stdin {}
      }
      output{
              stdout {}
      }
      
    • 실행

      # 명령어 실행
      $ ./logstash -f /elk/logstash/logstash/config/test.conf
      
    • 테스트

      [2022-04-08T13:57:59,153][INFO ][logstash.agent           ] Pipelines running {:count=>1, :running_pipelines=>[:main], :non_running_pipelines=>[]}
      The stdin plugin is now waiting for input:
      hello
      {
              "event" => {
              "original" => "hello"
          },
            "@version" => "1",
                "host" => {
              "hostname" => "localhost.localdomain"
          },
          "@timestamp" => 2022-04-08T04:58:42.697938Z,
            "message" => "hello"
      }
      
    • logstash-filebeat.conf 설정으로 실행

      • 설정

          #vi /elk/logstash/logstash/config/logstash-sample.conf
        
          input {
            beats {
              port => 5044
            }
          }
        
          output {
            elasticsearch {
              hosts => ["http://localhost:9200"]
              index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
              #user => "elastic"
              #password => "changeme"
            }
          }
        
      • 실행

        $ ./logstash -f /elk/logstash/logstash/config/logstash-sample.conf
        

        conf 파일은 절대 경로로 실행 할것 ../ 으로 경로로 실행할 경우 파일을 제대로 못찾는 버그가 있음



4. Filebeats 설치

설치 방법 : https://www.elastic.co/guide/en/beats/filebeat/8.1/filebeat-installation-configuration.html

설치 경로 : https://www.elastic.co/kr/downloads/beats/filebeat

filebeat는 권한 설정에서 excute 권한은 필히 주지 않을것!!

  • filebeat.yml 설정

    참고 링크: https://m.blog.naver.com/ksh60706/221729113310

    # vi /elk/filebeat/filebeat/filebeat.yml
    
    # ========================= Filebeat inputs ==========================
    - type: log
      enabled: true
    
      paths:
        # 수집할 로그 위치
        - /winitech/kacl/logs/*.log
    
      fields:
        # 수집하는 서버 명치
        server_name: kacl
        # 수집하는 서버 로그 타입
        log_type: apache-access
    
      # 패턴을 통해 log multiline 설정 ( 기준 timestamp )    
      multiline.pattern: '^[[0-9]{4}-[0-9]{2}-[0-9]{2}'
      multiline.negate: true
      multiline.match: after
    
    
    # ============================== Outputs ==============================
    
    # Elasticsearch Output 주석 처리하기
    
    # --------------------------- Logstash Output --------------------------
    output.logstash:  
      hosts: ["localhost:5044"]
    
    
  • 실행

    $ ./filebeat -e -c filebeat.yml
    
  • filebeat config 연결 테스트

    $ ./filebeat test output --path.config /elk/filebeat/filebeat
    


5. Logstash Filter 적용

Logstash에서는 Filter를 통해 읽어 들이는 로그를 추출함

추출은 Grok 패턴을 따름

grok 정규식 예제 : https://github.com/logstash-plugins/logstash-patterns-core/blob/main/patterns/ecs-v1/grok-patterns

log 형태 참고 링크 : https://umbum.dev/1144

grok 정규식 테스트 사이트 링크 :

  1. http://grokconstructor.appspot.com/do/match
  2. http://grokdebug.herokuapp.com/

grok 패턴 https://m.blog.naver.com/brilliantjay/221346745139

  • SpringBoot logback.xml 설정

    ``` 생략
    <!-- 로그 패턴 -->
    <property name="CONSOLE_LOG_PATTERN"
        value="%d{yyyy-MM-dd HH:mm:ss.SSS} %level %relative --- [ %thread{10} ] %logger{20} : %msg%n"/>  
    

    패턴에 특수 함수 들은 logstash 가 읽어들이때 특수 문자로 치환되므로 제거해야함

  • logstash.yml 설정

    # vi /elk/logstash/logstash/config
    
    input {
      beats {
        port => 5044
      }
    }
    
    filter {
      grok {
        match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:logLevel} %{BASE10NUM} --- \[ %{GREEDYDATA:thread} \] %{GREEDYDATA:logger} \: %{GREEDYDATA:msg}" }
      }
    
      date {
        match => ["timestamp", "yyyy-MM-dd HH:mm:ss.SSS"]
        target => "@timestamp"
        timezone => "Asia/Seoul"
      }
    }
    
    output {
      elasticsearch {
        hosts => ["http://localhost:9200"]
        index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
        #user => "elastic"
        #password => "changeme"
      }
    }
    
  • grok 예제

    • 원문

      2022-04-11 15:06:27.324 ERROR         19496 --- [ Camel (camel-1) thread #12 - timer://EAWS ] c.w.cs.CAMEL.Kacl003 : EAWS org.springframework.web.client.HttpClientErrorException$NotFound: 404 : [{"timestamp":"2022-04-11T06:06:27.881+00:00","status":404,"error":"Not Found","message":"","path":"/EQCALL"}]
      
    • grok

      %{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:logLevel} .*%{BASE10NUM:num} --- \[ %{GREEDYDATA:thread} \] %{GREEDYDATA:logger} \: %{GREEDYDATA:msg}
      
    • 결과

      {
        "timestamp": [
          [
            "2022-04-11 15:06:27.324"
          ]
        ],
        "YEAR": [
          [
            "2022"
          ]
        ],
        "MONTHNUM": [
          [
            "04"
          ]
        ],
        "MONTHDAY": [
          [
            "11"
          ]
        ],
        "HOUR": [
          [
            "15",
            null
          ]
        ],
        "MINUTE": [
          [
            "06",
            null
          ]
        ],
        "SECOND": [
          [
            "27.324"
          ]
        ],
        "ISO8601_TIMEZONE": [
          [
            null
          ]
        ],
        "logLevel": [
          [
            "ERROR"
          ]
        ],
        "num": [
          [
            "19496"
          ]
        ],
        "thread": [
          [
            "Camel (camel-1) thread #12 - timer://EAWS"
          ]
        ],
        "logger": [
          [
            "c.w.cs.CAMEL.Kacl003 : EAWS org.springframework.web.client.HttpClientErrorException$NotFound: 404"
          ]
        ],
        "msg": [
          [
            "[{"timestamp":"2022-04-11T06:06:27.881+00:00","status":404,"error":"Not Found","message":"","path":"/EQCALL"}]"
          ]
        ]
      }
      


op1. 방화벽 설정

9200 : elasticsearch

5601 : kibana

# elasticsearch
$ firewall-cmd --zone=public --permanent --add-port=9200/tcp

# kibana
$ firewall-cmd --zone=public --permanent --add-port=5601/tcp

# logstash
$ firewall-cmd --zone=public --permanent --add-port=5044/tcp

# 재기동
$ firewall-cmd --reload


99. 추가 설정

1) 심볼링크 설정

  • 심볼링크 설정:
    # 각 해당 경로에서 아래 명령어 적용
    
    # elasticsearch
    $ ln -s elasticsearch-7.9.1-linux-x86_64 elasticsearch
    
    # kibana
    $ ln -s kibana-8.1.1 kibana
    
    # logstash
    $ ln -s logstash-8.1.2 logstash
    
    

2) alias 설정

  • alias 추가

    #vi /etc/bashrc
    
    # elasticsearch
    alias es="cd /elk/elasticsearch/elasticsearch"
    
    # kibana
    alias kiba="cd /elk/kibana/kibana"
    
    # logstash
    alias logs="cd /elk/logstash/logstash"
    
  • alias 적용

    $ source /etc/bashrc
    

3) 서비스 등록

  • systemctl 등록 :

    엘라스틱서치를 시작할때 systemctl 쓰지말자 : https://aimb.tistory.com/225

    라는 의견도 있으니 참고 할것

    • elasticsearch.service

      #vi /lib/systemd/system/elasticsearch.service
      
      
      [Unit]
      Description=Elasticsearch Cluster
      Documentation=https://www.elastic.co/kr/products/elasticsearch
      Wants=network-online.target
      After=network-online.target
      
      [Service]
      RuntimeDirectory=elasticsearch-8.1.1
      WorkingDirectory=/elk/elasticsearch/elasticsearch
      
      LimitMEMLOCK=infinity
      LimitNOFILE=65535
      LimitNPROC=4096
      
      ExecStart=/elk/elasticsearch/elasticsearch/bin/elasticsearch
      ExecReload=/elk/elasticsearch/elasticsearch/bin/elasticsearch
      RestartSec=3
      
      User=wini
      Group=root
      
      [Install]
      WantedBy=multi-user.target
      
    • kibana.service

      # vi /lib/systemd/system/kibana.service
      
      [Unit]
      Description=Kibana 8.1
      
      [Service]
      RuntimeDirectory=Kibana 8.1
      WorkingDirectory=/elk/elasticsearch/elasticsearch
        
      Environment=CONFIG_PATH=/elk/kibana/kibana/config/kibana.yml
      ExecStart=/elk/kibana/kibana/bin/kibana
      ExecReload=/elk/kibana/kibana/bin/kibana
        
      User=wini
      Group=root
        
      [Install]
      WantedBy=multi-user.target
      
    • logstash.service

      # vi /lib/systemd/system/logstash.service
      
      [Unit]
      Description=logstash 8.1.2
      
      [Service]
      RuntimeDirectory=logstash 8.1.2
      WorkingDirectory=/elk/logstash/logstash
      
      ExecStart=/elk/logstash/logstash/bin/logstash -f /elk/logstash/logstash/config/logstash.yml
      ExecReload=/elk/logstash/logstash/bin/logstash
        
      User=wini
      Group=root
        
      [Install]
      WantedBy=multi-user.target
      
    • filebeat.service

      # vi /lib/systemd/system/filebeat.service
      
      [Unit]
      Description=Filebeat sends log files to Logstash or directly to Elasticsearch.
      Documentation=https://www.elastic.co/products/beats/filebeat
      Wants=network-online.target
      After=network-online.target
      
      [Service]
      
      Environment="GODEBUG='madvdontneed=1'"
      Environment="BEAT_LOG_OPTS="
      Environment="BEAT_CONFIG_OPTS=-c /elk/filebeat/filebeat/filebeat.yml"
      Environment="BEAT_PATH_OPTS= --path.data /elk/filebeat/filebeat/data"
      
      ExecStart=/elk/filebeat/filebeat --environment systemd $BEAT_LOG_OPTS $BEAT_CONFIG_OPTS $BEAT_PATH_OPTS
      
       ExecStart=/elk/filebeat/filebeat/filebeat -e -c /elk/filebeat/filebeat/filebeat.yml
      
      Restart=always
      
      [Install]
      WantedBy=multi-user.target
      
    • systemctl 적용

      $ systemctl daemon-reload
      


99. 이슈 사항

1. max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

title

elasticsearch 구동 메모리 부족에 의한 오류

참조 링크 : https://security-log.tistory.com/37


<<해결방법>>

  • vm max 메모리 수정

    #vi /etc/sysctl.conf		
    
    vm.max_map_count=262144
    
  • 적용

    $ sudo sysctl -w vm.max_map_count=262144
    


2. max file descriptors [4096] for elasticsearch process is too low, increase to at least [65535]

ERROR: [2] bootstrap checks failed. You must address the points described in the following [2] lines before starting Elasticsearch.
bootstrap check failure [1] of [2]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65535]
bootstrap check failure [2] of [2]: memory locking requested for elasticsearch process but memory is not locked

1개의 세션당 열 수있는 file descriptors 부족 오류

참조 링크 : https://soye0n.tistory.com/170

<<해결방법>>

  • file descriptors 수정

    #vi /etc/security/limits.conf
    
    ## 마지막 줄에 추가
    
    # 모든 세션 각 option 마다 65536으로 설정(Optional)
    #* hard nofile 65536 
    #* hard nofile 65536 
    #* hard nproc 65536  
    #* sort nproc 65536
    
    # 모든 세션 모든 option을 unlimited 설정
    * - memlock unlimited
    
  • max_map_count 추가

    #vi /etc/rc.local
    
    echo 1048575 > /proc/sys/vm/max_map_count
    
    #vi /etc/sysctl.conf
    
    vm.max_map_count=262144
    
  • memlock 설정 확인

    $ ulimit -l
    

 

 

** 원문과 스크립트는 Git에 있습니다.

https://github.com/taehyeon3549/StudyAllOfThings/tree/master/ELK

 

GitHub - taehyeon3549/StudyAllOfThings: 자라 나라 지식 지식~!

자라 나라 지식 지식~! Contribute to taehyeon3549/StudyAllOfThings development by creating an account on GitHub.

github.com

 

배포시 문제 발생으로는

 

1. jar 생성 안됨

2. Mainfest 없음

3. webservelt 없음

 

가 주로 있다.

 

구글링을 통해 JAR 파일 생성시 

 

jar.enabled = true를 해주고

 

Gradle Task로 

clean - jar - build를 했으나 오류 발생

 

 

해결방법]

 

build.gradle 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bootJar {
   jar.enabled = true // 빌드시 jar 을 실행
}
 
jar {    
   manifest { // 빌드시 Main-Class 설정
       attributes 'Main-Class': 'com.testing.test.TestingApplication'
    }    
}
cs

 

Gradle Tasks

 

Clean - bootJar 순으로 실행

 

로컬 서버나 TestBed 서버에서 해당 jar 파일

 

java -jar _____.jar 해서 실행

실서버 배포 이후 유지보수를 할때,

90% 이상이 쿼리나 웹 단 쪽 수정이 대부분.

 

그럴때마다 새롭게 jar파일을 만들어서 배포 할순 없으니

WEB-INF 와 .xml 을 외부로 빼서 이후에 수정을 할 수 있겠끔 설정을 하는 것이 필요.

 

 

1. application.properties에서

    spring.resource.static-locations = 리소스파일 경로

    spring.datasource.config-location = DB config 파일 경로

    를 설정 해준다.

 

2. DB config 파일에서 불러올 .xml 파일 경로 설정

 

3. jar 파일을 실행 시킬때 외부 properties 실행 옵션을 준다.

  ex) nohup java -jar ______.jar --spring.config.location='내 properties'

 

 

  • application.properties
1
2
3
4
5
6
7
8
9
10
11
# DB 설정    
 
# 기존 환경 설정 방식
spring.datasource.config-location=classpath:/mybatis/HELP/SqlMapConfig.xml
# 내 설정 파일 위치 지정(url or file)
spring.datasource.config-location=file://'파일경로위치'/SqlMapConfig.xml
 
# Resource 설정
 
#WEB-INF 와 같은 resource 위치 지정 (url or file)
spring.resources.static-locations=file://'파일경로위치'
cs

 

  • SqlMapConfig.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
 
    
<configuration>
    <settings>
      <setting name="callSettersOnNulls" value="true"/>
      </settings>
      
    <mappers>
        <!-- 기존 resource 형태 mapping -->
        <mapper resource="mybatis/AMM/job.xml"></mapper>
 
        <!-- url을 통한 file mapping -->
        <mapper url="file://'파일경로위치'/job.xml"></mapper>
    </mappers>  
</configuration>   
cs

 

  • 전체 형태

 

[파일전송]

 

pscp -P 22 '윈도우파일경로' '리눅스계정'@'리눅스ip':'리눅스디렉토리경로'

 

-P를 안붙이면 ssh_ini: Network error: Cannot assign requested address 오류 발생

 

[rpm설치]

rpm이 이동된 디렉토리

 

rpm -ivh '자바설치명'.rpm

 

 

 

 

 

 

회사에서 사용하려는 open JDK는 Azul 의 Java 11 입니다.

첫 사업이라 미리 공부할겸해서 로컬로 환경설정하는 도중 Open JDK 설정도 하고,

만났던 오류 해결 방법을 정리 해보겠습니다.

 

www.azul.com/downloads/zulu-community/?architecture=x86-64-bit&package=jdk

 

Download OpenJDK Open Source Java Zulu Linux Windows macOS

Download Java 11 Zulu OpenJDK Linux Windows macOS Solaris Update open source Java Alpine Java SE free download Java 8 Java 7 Java 6 JDK

www.azul.com

 

jdk버전에 맞는 apache Tomcat 버전 확인

 

http://tomcat.apache.org/whichversion.html

 

Apache Tomcat® - Which Version Do I Want?

Apache Tomcat® is an open source software implementation of a subset of the Jakarta EE (formally Java EE) technologies. Different versions of Apache Tomcat are available for different versions of the specifications. The mapping between the specifications

tomcat.apache.org

결론은 상관없습니다 ㅎㅎㅎㅎㅎ 그래서 최신 버전인 9로 설치,

 

https://tomcat.apache.org/download-90.cgi

 

Apache Tomcat® - Apache Tomcat 9 Software Downloads

Welcome to the Apache Tomcat® 9.x software download page. This page provides download links for obtaining the latest version of Tomcat 9.0.x software, as well as links to the archives of older releases. Unsure which version you need? Specification version

tomcat.apache.org

 

*자바 환경변수는 꼭 잡으셔야 됩니다.

 

sts 에서 maven 프로젝트 생성하는데 archtype은 (maven-archtype-web)으로 생성.

그리고 JRE 설정

 

 

 

1. HttpServlet 오류

 

server 창 열기

window - show view - other 에서 검색해서 찾기

다운 받은 apache 서버 설정

servers tab 에서 다운 받은 apache 버전 설정

중요! 꼭 JRE는 OpenJDK로 설정 해주기!!

 

 tomcat 설치 된 경로 잡아주고 JRE 꼭 OpenJDK로 잡아주기

프로젝트 설정에서 Java 버전 다시 잡아주고, Runtime 설정 해주기

Runtimes 에서 설정잡은 tomcat 체크 하기

 

 

2. Port 오류

 

이후 실행 하면 사진과 같이 오류가 뜬다,

포트에 문제가 있습니다?

포트 설정이 안잡혀서 오류가 뜨는것이기에 포트 잡아주고, 포트는 현재 사용중인 포트 말고 잡아 줍니다.

 

Tomcat admin port 설정 해주기

 

netstat -ano 로 사용중인 프로토콜 확인

 

 

 

그럼 이후 정상적으로 동작합니다.

 

그럼 화이팅

https://wnsgml972.github.io/mqtt/2018/03/05/mqtt/

 

MQTT 프로토콜 분석

MQTT란? MQTT(Message Queue Telemetry Transport)란 Broker Pattern을 이용한 메시징 프로토콜이다. Telemetry 장치, M2M(Machine to Machine, 사물지능통신), IoT(Internet of Things, 사물인터넷)에서 사용하기 위해 만들어졌으�

wnsgml972.github.io

 

 

https://hamait.tistory.com/390

 

MQTT 와 모스키토(Mosquitto) 란 무엇인가?

MQTT 시작하기 좋은 글 https://dzone.com/refcardz/getting-started-with-mqtt MQTT 란? (http://www.codejs.co.kr/mqtt-mq-telemetry-transport%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0/ 펌) [MQTT 프로토콜 설계..

hamait.tistory.com

 

 

 

https://dzone.com/refcardz/getting-started-with-mqtt

 

Getting Started With MQTT - Dzone Refcardz

While HTTP is the de-facto protocol for the human web, communication between machines at scale requires a paradigm shift. This is where the massively scalable and easy to implement protocol MQTT enters the picture. The DZone MQTT Refcard explores the funda

dzone.com

 

 

'머리 뜯으며 개발 > MQ' 카테고리의 다른 글

RabbitMq 무작정 설치하기  (0) 2022.06.13

TabControl의 탭 이동을 해서 새로운 탭이 열리면 서버로부터 값을 들고 오는 코드인데,

ListView를 클릭했는데도 SelectionChanged 이벤트가 발생되면 ListView가 계속 초기화된다.

 

scrawled-note.tistory.com/entry/WPF-C-TabControl%EC%9D%98-Tab-%EC%84%A0%ED%83%9D-%EC%9D%B4%EB%B2%A4%ED%8A%B8

 

WPF, C# ] TabControl의 Tab 선택 이벤트

Tab Item의 selected 이벤트로 동작할것이라 생각하고 접근했지만, selected 이벤트도 없고, MouseLeftDown 이벤트로 동작할꺼라 또! 생각했지만 틀렸다.... 방법 : TabControl의 SelectionChanged 이벤트를 통해..

scrawled-note.tistory.com

 

하단의 리스트를 클릭했지만...
탭을 클릭했을때 Log가 찍힌다?

 

 

 

 

EventArgs의 Source가 내가 발생신킨 TabControl가 맞는 확인하는 조건문 추가해서 동작시키면 해결

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.Source is TabControl)
            {
                Console.WriteLine("인덱스 클릭");
 
                string tabItem = ((sender as TabControl).SelectedItem as TabItem).Header as string;
                Console.WriteLine("tabItem >>" + tabItem);
 
                switch (tabItem)
                {
                    case "일반":
                        setUserInfo();
                        Console.WriteLine("1번 인덱스 클릭");
                        break;
                    case "사용자 관리":
                        // 사용자 리스트 가져옴
                        getUserList();
                        break;
                    case "업무 관리":
                        getWorkList();
                        break;
                        // 업무 리스트 가져옴
 
                }
            }            
        }
cs

 

+ Recent posts