문제

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

코드

def solution(dirs):
    answer = 0
    num = {'U':(0,1),'D':(0,-1),'R':(1,0),'L':(-1,0)}
    res={}
    visited = set()
    x, y = 0, 0

    for i in dirs:
        nx, ny = x + num[i][0], y + num[i][1]
        if -5 <= nx <= 5 and -5 <= ny <= 5:
            if ((x, y), (nx, ny)) not in visited:
                answer += 1
                visited.add(((x, y), (nx, ny)))
                visited.add(((nx, ny), (x, y)))
            x, y = nx, ny

    return answer

풀이

  • 중복을 제외하고 방문한 선분을 체크하기
  1. 입력받는 문자열에 따라 이동하는 좌표값 딕셔너리를 구현.
  2. 입력에 따라서 x,y를 움직인다. -5 ~ 5의 범위는 넘어가면 continue 해준다,
  3. set()에 이동좌표를 넣어서 만약 그 좌표가 존재하지 않으면 answer+=1해주고, 존재하면 중복한 값이라고 판단하고 넘어간다.

문제

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

코드

def changeStrToInt(time):
        return int(time[0:2]) * 60 + int(time[3:])

def solution(book_time):
        sort_time = sorted([[changeStrToInt(i[0]), changeStrToInt(i[1]) + 10] for i in book_time])

    res = []

    for i in sort_time:
        if len(res)==0:
            res.append(i)
            continue
        for j in range(len(res)):
            if(i[0] >= res[j][1]):
                res[j] = res[j]+i
                break
        else:
            res.append(i)

    return len(res)

풀이

  • 빈틈없이 예약해서 최소의 방 개수를 구하자
  1. 문자열로 입력받은 시간을 분으로 그리고 int형으로 만들어주는 함수를 작성한다.
  2. 그 다음 변환한 시간을 바탕으로 정렬해준다
  3. 정렬한 시간을 바탕으로 res배열에 넣어준
    1. res배열이 비어 있으면 바로 넣어준다.
    2. res배열을 돌면서 각각의 res배열의 제일 마지막 시간이 현재 첫번째 시간보다 작으면 거기 넣어준다.
    3. 넣을 곳이 없으면 배열에 새롭게 추가한다.
  4. 방의 개수를 리턴해준다.

HTTP를 어떻게 안전하게 할 수 있을까?

  • http의 보안버전은 효율적이고 이식성이 좋고, 관리가 쉬워야 하며, 현실 세계의 변화에 대한 적응력이 좋아야한다. 또한 사회와 정부의 요구사항에도 맞아야한다.
  • 다음을 제공해주는 HTTP의 보안기술이 필요하다.
    • 서버 인증 : 클라이언트는 자신이 위조된 서버가 아닌 진짜와 이야기하고 있음을 알 수 있어야함
    • 클라이언트 인증 : 서버는 자신이 가짜가 아닌 진짜 사용자와 이야기하고 있음을 알 수 있어야 한다.
    • 무결성 : 클라이언트와 서버는 데이터가 위조되는것을 방지해야한다.
    • 암호화 : 클라이언트와 서버가 서로 안전하게 대화해야 한다.
    • 효율 : 저렴한 클라이언트나 서버도 이용할 수 있도록 알고리즘은 충분히 빨라야 한다.
    • 편재성(Ubiquity) : 프로토콜은 거의 모든 클라이언트와 서버에서 지원되어야 한다.
    • 관리상 확장성 : 누구든 어디서든 즉각적인 보안 통신을 할 수 있어야 한다.
    • 적응성 : 현재 알려진 최선의 보안 방법을 지원해야 한다.
    • 사회적 생존성 : 사회의 문화적, 정치적 요구를 만족시켜야 한다.

HTTPS

  • http를 안전하게 만드는 방식 중에서 가장 인기 있는 것
    • 보안 전송 계층을 통해 전송되는 http이다
  • 모든 주류 브라우저와 서버에서 지원한다.
    • firefox, safari, chore, edge 등등
  • 모든 http 요청과 응답 데이터는 네트워크로 보내지기 전에 암호화된다. https는 http의 하부에 “전송 레벨 암호 보안 계층”을 제공함으로써 동작.
    → 이 보안 계층은 안전 소켓 계층(SSL, Secure Sockets Layer)혹은 그를 계승한 전송 계층 보안(TLS, Transport Layer Security)을 이용하여 구현.
    → SSL과 TLS는 사실상 같기 때문에 SSL이라고 표기하기도 함
    • SSL : Netscape사에서 1995년에 만든 통신 프로토콜
    • TSL : SSL의 3.0버전을 가지고 Netscape가 개발에서 빠지며 국제 인터넷 표준화 기구 **IETF(Internet Engineering Task Force)**에서 만든 프로토콜
      ⇒ 현재는 SSL 2.0 및 3.0이 전부 사용 중지, 사실상 TLS만 사용.
      ⇒ 또한 TLS 1.0과 1.1도 사용 중지 예정
    • ![[123.png]]
      ![[765432.png]]
→ 대부분의 경우, tcp 입력/출력 호출을 ssl 호출로 대체하고, 몇가지의 설정만 바꿔주면 된다.
  • 인코딩 및 디코딩 작업은 대부분 SSL 라이브러리 안에서 일어나기 때문에 http의 로직을 크게 변경할 필요가 없다.
    → 대부분의 경우, tcp 입력/출력 호출을 ssl 호출로 대체하고, 몇가지의 설정만 바꿔주면 된다.

암호(cipher)

  • 암호 : 메시지를 인코딩하는 어떤 특정한 방법과 나중에 그 비밀 메세지를 디코딩하는 방법을 말함.
  • 원본 메세지(텍스트 or 평문)에 암호를 적용하면 암호문이 된다.

  • 역사상 최초의 암호 : 스키테일 암호

스키테일 암호

 

  • 카이사르의 순환암호
  • 메세지의 각 글자를 알파벳 순서상 세번 뒤의 글자로 바꾸는 방법 사용

순환암호

디지털 암호

  • 디지털 시대로 넘어오면서 두가지의 변화
    • 속도 및 기능에 대한 전폭적인 성장, 훨씬 더 복잡한 인코딩과 디코딩이 가능해짐
    • 매우 큰 키를 지원하는 것이 가능해져 단일 암호 알고리즘으로 키의 값마다 다른 수조개의 암호 알고리즘을 만들어 낼 수 있게 됨.
  • 평문 메세지 P, 인코딩 함수 E, 디지털 인코딩 키 e가 주어졌을 때 암호문 C를 생성할 수 있다.
    ![[62138761283.png]]
자세한 암호화에 관한 내용은 전 게시글에 존재한다
 

SSL/TLS란?

개요 SSL(Secure Sockets Layer) TLS(Transport Layer Security) 왜 SSL을 사용해야 하는가? 암호화 기법 SSL 인증서 SSL Handshake SSL(Secure Sockets Layer) ssl이란 "웹사이트의 ID를 인증하고 암호화된 연결을 생성하는 인

enochkon.tistory.com

 

사이트 인증서 검사

  • 날짜 검사
    • 인증서의 유효기간을 검사
  • 서명자 신뢰도 검사
    • 발급받은 CA가 믿을만한 기관인지 검사
  • 서명 검사
    • CA의 공개키를 사용해 인증서의 무결성 검증
  • 사이트 신원 검사
    • 인증서의 도메인 이름과 서버의 도메인 이름이 맞는지 검사

와이어 샤크로 ssl handshaking 뜯어보기

  • 와이어 샤크를 사용해서 naver에 접속할 때 ssl 인증이 어떻게 이루어지는지 확인하기
  • naver의 ip주소를 알아내기 위해서 nslookup 명령어 사용
    • 와이어샤크에서 ipv6를 사용하길래 네이버의 ipv6 주소를 알아냄

  • 와이어 샤크에서 naver의 ssl handshake만 보기 위해서 설정

 

  • 설정 후 네이버 창을 켠뒤 와이어샤크 측정 종료
  1. client hello
    • 클라이언트가 서버에 처음으로 연결을 요청할 때 보냄
    • client의 SSL 버전, 세션 ID, Cipher Suites 등을 보낸다.

 

2. server hello

  • 클라이언트의 응답을 받았으며 SSL/TLS Handshake 를 진행
  • 클라이언트에서 받은 Cipher Suites 목록 중에 사용할 버전 확정해서 응답

 

3. Certificate

  • 서버가 클라이언트에게 자신의 디지털 인증서를 제공
  • 이 메세지에 있는 디지털 인증서를 기반으로 클라이언트가 서버의 신뢰성을 확인.

 

4. Server Key Exchange

  • 서버 측에서 키 교환을 위해 서버의 인증서를 넘어서는 추가 데이터가 필요할 때 요청하는 메세지
    Server Hello Doine
    • ssl handshake에서 서버의 역할이 완료되었음을 알림 (서버가 보낼 건 다보냈다)
     

 

5. Client key Exchange

  • 클라이언트에서 공유할 비밀키 생성
    change Cipher Spec
  • 이제부터는 아까 위에서 협상했던 암호화 방법으로 통신을 전환하자고 알리는 것

 

6. New Session Ticket

  • 일종의 캐시 역할.
  • 클라이언트가 나중에 연결 시 빠른 연결을 위해 세션 티켓을 저장
    change Cipher Spec
  • 클라이언트의 요청과 똑같이 이제 암호화된 통신이라는 것을 의미

7. Application Data

  • 클라이언트에서 암호화된 통신으로 서버로 전송

 

8. Application Data

  • 서버에서도 클라이언트에 대한 응답으로 암호화된 데이터 전송

 

Reference

https://a-gyuuuu.tistory.com/357
https://doongdangdoongdangdong.tistory.com/249
https://mandoo12.tistory.com/26

'CS' 카테고리의 다른 글

흐름제어(flow control)와 혼잡제어(congestion control)  (0) 2024.01.19
SSL/TLS란?  (1) 2024.01.05

개요

  • SSL(Secure Sockets Layer)
  • TLS(Transport Layer Security)
  • 왜 SSL을 사용해야 하는가?
  • 암호화 기법
  • SSL 인증서
  • SSL Handshake

SSL(Secure Sockets Layer)

  • ssl이란 "웹사이트의 ID를 인증하고 암호화된 연결을 생성하는 인터넷 보안 프로토콜"
  • Netscape는 개발된 프로토콜로 SSL 1.0은 1995년 개발
    -> 하지만 1.0의 경우 많은 이슈가 있어 공개되지 않았고, 1996년에 2.0부터 공개되기 시작
  • 개인정보 보호, 인증, 데이터 무결성을 보장
  • 클라이언트와 웹 서버 사이에서 동작

TLS(Transport Layer Security)

  • SSL과 거의 동일한 프로토콜
  • 특정 회사(Netscape)에 의해 개발된 SSL을 인터넷 표준화 기구인 IETF (Internet Engineering Task Force)에서 표준화
  • SSL 3.0 버전을 기반으로 TLS 1.0을 발표
  • 윈도우에서 지원되는 SSL과 TLS

현재는 모든 SSL은 지원하지 않고, TLS만 사용한다.

왜 SSL을 사용해야 하는가?

  • ssl같은 보안을 적용하지 않고 그냥 데이터를 주고 받는다면 제 3자가 데이터를 쉽게 탈취할 수 있다.

SSL이 적용되지 않은 경우

  • ssl이 적용되지 않으면 위 그림에서 처럼 "High Value Information"라는 문자열이 그대로 전송
  • 제 3자가 데이터를 탈취하기 쉽다.

SSL 적용된 경우

  • ssl이 적용된 경우에는 데이터가 암호화되어서 보내진다.
  • 제 3자가 탈취한다 해도 복호화하기 힘들기 때문에 상대적으로 안전해진다.

암호화 방식

  • 사용하는 암호화 방식은 대칭키와 비대칭키를 혼합해서 사용한다.

대칭키 암호화

  • 대칭키 암호화 : 인코딩 할 때 사용하는 키와 디코딩 할 때 사용하는 키가 같다. (발송자와 수신자는 같은 비밀키를 알고 있어야 한다.
    ex) DES, Triple-DES, RC2, RC4

  • 비밀키의 보안이 제일 중요하다. 대부분의 경우, 인코딩&디코딩 알고리즘은 공개적으로 알려져 있어서 키를 알면 암호를 풀 수 있다.
  • 열거 공격(Enumeration Attack) : 가능한 모든 수를 대입해보기 (브루트포스)
    → 이를 방지하기 위해 키값을 늘림. 128비트의 암호키는 2의 128승 의 값이 가능…
        (340282366920938463463374607431768211456가지의 값)
  • 대칭키 암호의 단점
    • 발송자와 수신자가 동일한 공유키를 가져야함.
      → 발송자와 수신자의 수 만큼 키가 있어야함, 많은 수의 키를 관리해야함.
    • 공유키가 탈취되면 모든 문서의 암호가 풀릴 수 있음

공개키(비대칭키) 암호화

  • 공개키 암호화 : 두 개의 비대칭 키를 사용, 인코딩 키는 공개되어 있고 디코딩 키만이 보안 유지.
    ex) RSA
  • 호스트가 인코딩 키를 공개하면, 이 인코딩 키를 사용해서 호스트에게 암호화된 메세지를 보낼 수 있다.
    → 그리고 이 암호화된 메세지는 오직 호스트가 가지고 있는 디코딩 키를 사용해서 볼 수 있다.
  • 대칭키와는 달리 인코딩키를 공유하므로 키의 개수를 줄일 수 있다.

데이터 전달 과정

  1. 송신자가 수신자의 공개키를 사용해서 데이터를 암호화 한다.
  2. 수신자는 본인만이 가지고 있는 개인키를 사용해서 데이터를 복호화해서 사용한다.

공개키의 단점

  • 연산속도가 느리다.

디지털 서명

  • 공개키 암호화 방식을 사용해서 구현
  • 보내는 이의 개인키를 사용해서 서명을 작성 -> 받는 쪽에서 보낸이의 공개키를 사용해서 복호화

앨리스가 밥에게 보낼 때

  1. 앨리스는 밥의 공개키(PK/bob) 을 이용하여 암호화 한다.
  2. 앨리스는 앨리스의 개인키(SK/Alice)을 이용하여 서명한다.
  3. 밥은 밥의 개인키(SK/bob)을 이용하여 복호화 한다.
  4. 밥은 앨리스의 공개키(PK/Alice)을 이용하여 서명을 검증한다.(앨리스가 보낸사항임을 확인함)

앨리스가 밥에게 보낼 때 (해쉬 포함)

  1. 앨리스는 밥의 공개키(PK/bob) 을 이용하여 암호화 한다.
  2. 앨리스는 문서내용(Hello, Bob)을 해쉬한다.
  3. 이 해쉬에 앨리스의 개인키(SK/Alice)를 이용하여 서명한다.
  4. 밥은 밥의 개인키(SK/bob)을 이용하여 복호화 한다.
  5. 밥은 위의 복호화한 내용을 해쉬한다.
  6. 밥은 앨리스에게서 온 서명을 앨리스의 공개키(PK/Alice)을 이용하여 서명을 검증(복호화)한다.
  7. 위의 복호화된 값과, 5의 해쉬값이 일치하는지 확인한다. (앨리스가 보낸사항임을 확인함)

간단한 실습

대칭키

# txt 파일 생성
echo "hihihi" > aa.txt

# 1234라는 키를 사용해서 -aes-256-cbc 방법을 사용해서 암호화. 
openssl enc -aes-256-cbc -salt -in aa.txt -out ciphertext.bin -k 1234

# 같은키와 같은 방식으로 복호화
openssl enc -d -aes-256-cbc -in ciphertext.bin -out decrypted.txt -k 1234

비대칭키

# rsa방식으로 1024bit 길이로 키 생성
openssl genrsa -out private.pem 1024;

# private.pem에 대한 공개키 생성
openssl rsa -in private.pem -out public.pem -outform PEM -pubout;

# 공개키를 사용해서 파일 암호화
openssl pkeyutl -encrypt -inkey public.pem -pubin -in aa.txt -out file.ssl;

# 비밀키를 사용한 파일 복호화
openssl pkeyutl -decrypt -inkey private.pem -in file.ssl -out decrypted.txt

SSL 인증서

  • SSL 인증서는 클라이언트와 서버간의 통신을 제3자가 보증해주는 전자화된 문서
  • 보통 CA라고 불리는 공인된 기관에서 유료로 발급
  • 인증서 내용
    1. 서비스의 정보 (인증서를 발급한 CA, 서비스의 도메인 등)
    2. 서버 측 공개키 (공개키의 내용, 공개키의 암호화 방법)

CA

  • CA(Certificate authority) 혹은 Root Certificate 라고도 불림
  • 민간기업 중 엄격한 심사를 통해서 선정된 SSL 인증서 발급 기업
  • 이 CA는 기본적으로 브라우저에 내장되어 있다.

  • 맥의 경우 키체인에서 CA 인증서들을 확인할 수 있다.

SSL 인증서가 서비스를 보증하는 방법

  1. 웹 브라우저가 서버에 접속할 때 서버는 제일 먼저 인증서를 제공
  2. 브라우저는 이 인증서를 발급한 CA가 자신이 내장한 CA의 리스트에 있는지를 확인
  3. 확인 결과 서버를 통해서 다운받은 인증서가 내장된 CA 리스트에 포함되어 있다면 해당 CA의 공개키를 이용해서 인증서를 복호화
    => 인증서를 복호화 할 수 있다는 것은 이 인증서가 CA의 비공개키에 의해서 암호화 된 것을 의미
    => 즉 안전하다.

SSL Handshake

  • 파란 부분은 tcp handshake
  • 노란 부분이 ssl handshake
  1. ClientHello
    • client측에서 서버에 연결을 요청한다. (인사?)
    • session id, ssl protocol version, cipher suite 목록 등의 정보를 담아서 전송
  2. ServerHello & Certificate, ServerHelloDone
    ServerHello
    • 1번에서 클라이언트에서 받은 인사(Client Hello 패킷)에 대해 서버가 응답
    • ssl protocol version, client suite중 하나 선택해서 응답
      Certificate, ServerHelloDone
    • Server 의 SSL 인증서 내용을 클라이언트에게 전송
  3. client 에서 server 의 SSL 인증서 검증
    • 서버에서 받은 인증서 정보를 가지고 유효한 인증서인지 검증한다.
  4. Client Key Exchange
    • 서버의 인증서 검증을 마친 후, 클라이언트는 서버와 통신하기 위한 대칭키를 생성한다.
    • 이 생성한 대칭키를 서버의 공개키를 사용해서 암호화 해서 서버에게 전송한다.
  5. Server / Client SSL Handshake Finished
    • 서버가 암호화된 대칭키를 받아서 복호화에 성공하면 연결이 끝난다.

기타

무료 인증서 발급 사이트 목록

1. Let’s Encrypt : https://letsencrypt.org/
2. Comodo Free SSL : https://www.gogetssl.com/domain-validation/comodo-free-ssl/
3. CloudFlare One-Click SSL : https://www.cloudflare.com/ssl/
4. AWS Certificate Manager : https://aws.amazon.com/ko/certificate-manager/


Reference

https://hstory0208.tistory.com/entry/SSL-%EC%9D%B4%EB%9E%80-TLS-%EC%9D%B4%EB%9E%80
https://captcha.tistory.com/51
https://support.cafe24.com/hc/ko/articles/8469947344409-SSL%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94-
https://velog.io/@yjw8459/%EC%9B%B9-%EC%82%AC%EC%9D%B4%ED%8A%B8-%EB%B3%B4%EC%95%88-SSL%EC%9D%B4%EB%9E%80
https://12bme.tistory.com/80
https://arc.net/l/quote/gqzfvkyb

'CS' 카테고리의 다른 글

흐름제어(flow control)와 혼잡제어(congestion control)  (0) 2024.01.19
HTTPS와 SSL Handshake  (0) 2024.01.13

성능 분석이란?

성능 테스트

  • 실제 트래픽 상황에서의 정상 동작 하는지를 파악.

부하 테스트

  • 리소스 병목 탐색, 어플리케이션 버그 탐색
  • 이벤트 상황과 같은 순간 트래픽 최대치, 한계치를 탐색
  • 신규 스펙 장비에서 MYSQL 설정 최적화 탐색

스트레스 테스트

  • 장기간 부하 발생에 대한 한계치를 탐색, 예외 동작 상황 확인
  • Graceful Shutdown 정상 동작 확인
  • 데이터베이스 failover 상황, 자동 복구, 예외 동작 상황 확인
  • 외부 요인(PG사)의 밀릴, 예외 상황 동작 확인

성능 분석을 하는 이유

  • 서비스 및 서비스 시스템의 성능을 확인하기 위해 실사용 환경과 비슷한 환경에서 테스트를 진행하는 것
    • 어느 정도의 부하를 견딜 수 있는지
    • 한계치에서 병목이 생기는 지점 찾기
    • 자원을 효율적으로 사용할 수 있다.
    • 메모리 누수, 오류, 오버플로우 발생하는지 확인 가능
    • 최악의 상황에서 어떤 동작을 하는지 확인 가능
    • 장애 조치와 복구의 동작을 확인 가능
  • 구글 리서치 자료에 따르면 3초 이상 걸리면 53%의 사용자가 떠나며, 표시 속도가 1초에서 7초로 늘어난다면 이탈률은 113%가 된다고 함
 

Mobile conversion rate statistics - Think with Google

Google’s Official Mobile Marketing Publication. Mobile conversion rates are lower than on desktop. Get more mobile data on Think with Google.

www.thinkwithgoogle.com

→ 웹 성능테스트를 통해 사용자에게 빠른 서비스를 제공할 수 있어야 한다.

성능 테스트의 기대 효과

  1. 시스템 측면 : 주요 성능 결함 및 구조적 위험 우선 식별, 운영시스템 성능 최적화, 유지보수 비용 및 시
    스템 비용 최소화 등
  2. 사용자 측면 : 서비스의 품질 개선, 응답시간 향상을 통한 업무 효율 증대, 사용자 만족도 향상 등

nGrinder

 

nGrinder

Please post questions in Discussions not Issues. nGrinder 3.5.5-p1 version is now available. Check the changes at here. nGrinder is a platform for stress tests that enables you to execute script creation, test execution, monitoring, and result report gener

naver.github.io

  • nGrinder는 네이버에서 성능 측정 목적으로 jython(JVM위에서 파이썬이 동작)으로 개발 된 오픈소
    스 프로젝트이며,2011년에 공개 됨.
  • 실제 서비스에 투입 되기 전, 실제와 같은 환경을 만들어 놓고 서버가 사용자를
    얼마 만큼 수용할 수 있는지를 실험 할 때 사용
  • 언어로는 jython (java + python)과 Groovy(자바 호환)를 지원.

Controller

  • 퍼포먼스 테스팅(부하테스트)를 위해 웹 인터페이스를 제공
  • 테스트 프로세스를 체계화
  • 테스트 결과를 수집해 통계로 보여줌

Agent

  • Controller의 명령을 받아 실행.
  • target이 된 머신에 프로세스와 스레드를 실행시켜 부하를 발생.
  • 대상 시스템의 CPU와 Memory를 모니터링.

Target

  • 부하 테스트를 받는 머신

설치 방법

  • controller와 agent를 둘다 설치해야 한다.

docker를 사용하는 방법

  • 운영 체제별 도커 데스크탑 설치
 

Docker Desktop: The #1 Containerization Tool for Developers | Docker

Docker Desktop is collaborative containerization software for developers. Get started and download Docker Desktop today on Mac, Windows, or Linux.

www.docker.com

  • 우분투 도커 설치
 

Ubuntu 에 Docker 설치

실행환경 Ubuntu 22.04 Docker 설치방법 1. 우분투 시스템 패키지 업데이트 sudo apt-get update 2. 필요한 패키지 설치 sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common 3. Docker의

haengsin.tistory.com

  • controller 설치 및 실행
# docker hub에서 이미지 가져오기
docker pull ngrinder/controller

# 가져온 이미지로 실행하기
docker run -d -v ~/ngrinder-controller:/opt/ngrinder-controller --name controller -p 80:80 -p 16001:16001 -p 12000-12009:12000-12009 ngrinder/controller
  • agent 설치 및 실행
# docker hub에서 이미지 가져오기
docker pull ngrinder/agent

# 가져온 이미지로 실행하기
# 위에서 생성했던 controller와 연결
docker run -d --name agent1 --link controller:controller ngrinder/agent

직접 파일을 다운로드해서 실행시키는 방법

이 경우에 자바를 사용해야한다.

  • 자바 다운로드
 

Java를 설치하는 방법은 무엇입니까?

 

www.java.com

  • nGrinder 다운로드
    • 받고싶은 버전(보통은 최신버전)을 선택하여 .war 파일을 다운 받는다.
 

Releases · naver/ngrinder

enterprise level performance testing solution. Contribute to naver/ngrinder development by creating an account on GitHub.

github.com

  • 다음 받은 후 해당 명령어를 실행한다.
# java -Djava.io.tmpdir=[임시파일을 저장할 경로] -jar [다운받은 war 파일 이름] --port=[열고싶은 포트번호]
# 예시
java -Djava.io.tmpdir=/Users/choi/Desktop/test/ -jar ngrinder-controller-3.5.8.war --port=8301
  • 정상적으로 실행 되었다면 localhost:[지정한 포트]로 접속할 시 nGrinder 메인 화면이 뜬다

  • 초기 관리자 ID와 password는 둘다 admin이다.
  • 접속 후 오른쪽 상단의 admin 클릭 후 에이전트 다운로드 클릭 해서 압축 파일 다운로드

  • 다운받은 압축 파일을 압축해제 해제
# tar -xvf [다운받은 압축파일]
tar -xvf ngrinder-agent-3.5.8-localhost.tar
  • 압축 해제 후 run_agent.sh 실행 (윈도우는 .bat)

./run_agent.sh
  • 이렇게 실행할 경우 agent도 틀어짐

사용 방법

 

에이전트 테스트에 사용할 에이전트의 개수
스크립트 사용자가 해당 주소로 부하를 걸 스크립트를 보여줌
RHEAD 선택된 스크립트의 내용을 보여주는 페이지로 이동
테스트 대상 서버 테스트를 진행할 서버의 리스트를 보여주며, 추가버튼 클릭 시 테스트 받을 서버를 늘릴 수 있다.
테스트 기간 해당 테스트를 얼마만큼 실행할 지 설정하는 항목
실행 횟수 사용자가 설정한 쓰레드당 몇 번의 테스트를 실행할 것인지를 지정
Ramp-Up 점차 부하를 가할 수 있는 기능. 부하를 가할 때, 가상 사용자 수를 늘리는 것 이 아닌 process나 thread를 늘린다
초기 개수 처음 시작 시 가상사용자의 수를 설정
초기 대기 시간 테스트를 언제부터 실행시킬 지 설정
증가 단위 해당 process/thread를 몇 개씩 증가시킬지를 설정
Ramp_Up 주기 상승 시간을 설정

  • 여러가지 스크립트를 작성해서 각 기능에 대해 얼마나 부하가 걸리는지 확인할 수 있다.
// 로그인 페이지 예시 스크립트
@Test
public void testLogin() {
    // 메인 페이지 요청
    HTTPResponse mainPageResponse = request.GET("http://example.com/main")

    // 로그인 요청
    Map<String, Object> loginParams = [username: "user", password: "pass"]
    HTTPResponse loginResponse = request.POST("http://example.com/login", loginParams)

    // 로그인 응답 확인
    assertThat(loginResponse.statusCode, is(200))

}

 

🚀NCP와 깃허브 액션을 통한 CI/CD 구현기🚀

  1. ncp에서 배포 할 ubuntu server 생성
  2. npc에서 docker image를 저장할 object storage와 container registry 생성
  3. vite+react+typscript의 프론트 레포에서 배포할 dockerfile 작성
  4. 배포를 위한 github action 등록

NCP에서 ubuntu server 생성

네이버 클라우드 계정에서 server 생성

  • 서버는 유지비를 생각해서 micro로 생성했다. (최초 결제수단 등록 시 1년간 하나의 micro 서버 무료)

  • 새로운 인증키를 생성 후 다운받아 둔다.

  • 새로운 ACG(Access control group, 보안 그룹)을 생성해준다.
    • 임시로 0.0.0.0/0으로 열어두었다.
    • 보안을 위해서는 특정 주소에서만 접근할 수 있게 지정해주면 좋다.

  • 서버 생성 후 “운영중”이 뜰때까지 기다린다.

  • 서버가 생성되었다면 접속을 위해 포트포워딩을 설정해주어야 한다.
  • “외부 포트”에 임의의 포트번호를 입력 후 추가를 해준다.

  • 서버에 연결하기 위한 비밀번호를 설정해준다.
  • 생성한 서버 클릭 후 “서버 관리 및 설정 변경” → “관리자 비밀번호 확인”

  • 아까 서버를 생성할 때 다운받아 놨던 .pem 파일을 넣은 후 “비밀번호 확인”클릭

  • 그렇게 되면 관리자 이름과 비밀번호가 뜨게 되는데, 최초 접속 시 비밀번호로 복사해서 기록해 놓는다.
    • 보통 관리자 이름은 root다.

 

생성한 서버에 접속하기

  • 위에서 만든 서버에 접속해 본다.
  • “포트포워딩” 탭에서 설정했던 포트번호와, 거기에 있는 공인 ip를 활용해서 서버에 접속한다.
  • ssh 연결 시 비밀번호를 입력해달라고 하는데, 바로 위에서 복사해두었던 최초 접속 시 비밀번호를 넣어준다.
ssh -l root -p [포트번호] [공인 ip]
  • 접속 완료

  • 서버에 접속했으면 배포 시 사용할 도커를 설치해준다.

우분투 서버에 도커 설치

1. 우분투 시스템 패키지 업데이트

sudo apt-get update

2. 필요한 패키지 설치

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

3. Docker의 공식 GPG키를 추가

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

4. Docker의 공식 apt 저장소를 추가

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

5. 시스템 패키지 업데이트

sudo apt-get update

6. Docker 설치

sudo apt-get install docker-ce docker-ce-cli containerd.io

7. Docker가 설치 확인

7-1 도커 실행상태 확인

sudo systemctl status docker

7-2 도커 실행

sudo docker run hello-world

출처

[Docker] Ubuntu 22.04 Docker 설치

 

Object Storage, Container Registry 생성

  • 도커 이미지를 저장하고 가져다 쓰기 위한 Object Storage와 Container Registry를 생성해준다.

Object Storage 생성

  • Object Storage 이용 신청
  • 이용 신청 후 버킷 생성

  • 이름 입력 후 설정 건드리지않고 “다음” 버튼 클릭 후 버킷 생성



Container Registry 생성

  • Container Registry로 이동 후 “레지스트리 생성” 클릭

  • 이름 입력 및 생성한 Object Storage 넣은 후 생성



vite+react+typescript에서 Dockerfile 만들기

  • 배포할 프로젝트 최상단에 nginx를 사용하여 배포하는 Dockerfile을 생성
  • (참고로 현재 배포에 사용하는 gihub repo가 client와 server둘다 있어서 프론트 코드는 /client에 들어가 있다.)

# 첫 번째 단계: 빌드 환경 구축
FROM node:lts-alpine as build-stage

WORKDIR /app

# 의존성 파일 복사 및 설치
# COPY [내 package.json 파일과 yarn.lock 파일의 경로] [복사할 위치]
COPY ./client/package.json ./client/yarn.lock ./
RUN yarn install && yarn global add typescript

# 소스 코드 복사
COPY ./client .

RUN ls -l
# 애플리케이션 빌드
RUN yarn build

# 두 번째 단계: Nginx를 사용하여 애플리케이션 서빙
FROM nginx:stable-alpine as production-stage

# 빌드된 파일을 Nginx 서버로 복사
COPY --from=build-stage /app/dist /usr/share/nginx/html

# 80 포트 노출
EXPOSE 80

# Nginx 실행
CMD ["nginx", "-g", "daemon off;"]

 

CLI로 container registry에 도커 이미지 build,push 하기

NCP container registry에 로그인하기 위해서는 마이페이지에서 인증키 생성이 필요하다.

  • 마이페이지 - 계정관리 - 인증키관리 - 신규 API 인증키 생성 - Access Key ID, Secret Key가 각각 ID, PW로 로그인시 사용된다.
  • 해당 repository에 접근하기 위해서는 로그인이 필요하다.
  • Registry URL은 Container Registry에서 생성한 레지스트리를 클릭하면 Public Endpoint가 있는데 그것을 사용해주면 된다.
docker login <CONTAINER_REGISTRY_URL>
  • 다음을 입력하면 usernamepassword를 입력하라고 나오는데, 위에서 발급한 Access Key ID를 username으로, secret key를 password로 입력하면 된다.
  • 도커 파일을 작성한 배포할 프로젝트의 최상단에서 다음 명령어를 쳐주면 build되고 push되어서 Container Regisrty에 반영된다.
docker build -t <CONTAINER_REGISTRY_URL>/<TARGET_IMAGE[:TAG]> .
docker push <CONTAINER_REGISTRY_URL>/<TARGET_IMAGE[:TAG]>

 

깃허브 액션을 이용해 ci/cd 구축

깃허브 액션을 위한 .yml 파일 작성

  • 이제 ci/cd 구축을 위해 특정 브랜치가 push, merge 등 업데이트 될 때 마다 build 후 배포되게 깃허브 액션으로 등록 한다.
  • 레포에서 .github/workflows에 deploy.yml 파일을 생성한다.
name: auto deploy #작업 이름

on:
  push:
    branches:
      - dev # dev branch가 push 될때 실행

jobs:
  docker_push_front: #도커파일에 작성된 내용을 바탕으로 이미지를 push한다.
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Login to NCP Container Registry
        uses: docker/login-action@v2
        with: #container registry에 연결
          registry: ${{ secrets.NCP_CONTAINER_REGISTRY }}
          username: ${{ secrets.NCP_ACCESS_KEY }}
          password: ${{ secrets.NCP_SECRET_KEY }}

      - name: Build and Push Docker Image
        uses: docker/build-push-action@v3
        with: # 도커파일에 작성된 내용으로 이미지를 빌드, container registry에 push한다.
          context: .
          file: ./client/Dockerfile  
          push: true
          tags: ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
          cache-from: type=registry,ref=${{ secrets.NCP_CONTAINER_REGISTRY }}/front
          cache-to: type=inline

  docker_pull_front:
    name: Connect server ssh and pull frontend from container registry
    needs: docker_push_front #위의 push가 진행 된 후
    runs-on: ubuntu-latest
    steps: # container registrty에 push된 
      - name: connect ssh
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.FRONT_HOST }}
          username: ${{ secrets.FRONT_USERNAME }}
          password: ${{ secrets.FRONT_PASSWORD }}
          port: ${{ secrets.FRONT_PORT }}
          script: |
            docker pull ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
            docker stop $(docker ps -a -q)
            docker rm $(docker ps -a -q)
            docker run -d -p 80:80 ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
            docker image prune -f

 

깃허브 secret 등록

  • 깃허브 액션이 제대로 작동하기 위해서 serect을 등록한다.
  • github 레포에서 settings → secrets and variables → actions로 가서 “new repository secret”르 누른 후 다음과 같이 이름과 그 값을 추가한다.

컨테이너 레지스트리 연결할 때 사용하는 값들

  • NCP_CONTAINER_REGISTRY : 컨테이너 레지스트리의 Public Endpoint
  • NCP_ACCESS_KEY : mypage에서 발급 받은 Access Key ID
  • NCP_SECRET_KEY : mypage에서 발급 받은 secret key
  • FRONT_HOST : 포트포워딩 탭에서 설정했던 서버 접속 공인 ip
  • FRONT_PORT : 포트포워딩 탭에서 설정했던 포트번호
  • FRONT_USERNAME : 관리자 비밀번호 설정에서 확인했던 관리자 이름 (보통 초기에는 root)
  • FRONT_PASSWORD : 관리자 비밀번호 설정에서 확인했던 비밀번호

→ 추가 후 dev 브랜치에 push가 일어나게 되면 자동으로 server에 빌드 및 배포가 이루어진다.



서버 공인 ip 설정

  • 지금까지 사용했던 ip는 “서버 접속용 공인 ip”다.
  • 실제로 배포한 server에 접속하기 위해서는 공인 ip가 필요하다.
  • server의 public ip로 이동

  • 공인 ip 신청, 처음 만들었던 서버를 적용 서버로 선택 연결



완성

  • 이제 설정한 공인 ip로 접속할 경우 배포되어있는 것을 확인할 수 있다.

Reference

https://sungbin.dev/post/NCP Container Registry를 활용하여 CI·CD 환경 구축하기

EC2 구성하기

key pair 생성

ec2를 접속할 때 사용할 key pair를 생성한다.

ssh-keygen -t rsa -b 4069 -C {자신의 메일} -f "./my_key" -N ""
# rsa 방식으로 4096비트를 사용해서 생성한다.

생성 완료되면

Generating public/private rsa key pair.
Your identification has been saved in ./my_key
Your public key has been saved in ./my_key.pub
The key fingerprint is:
SHA256:[여러 문자] [입력한 메일 주소]
The key's randomart image is:
+---[RSA 4069]----+
|+O               |
|++@+.   . .      |
|oo.+   + o +     |
|=.  o o +        |
|E..  . .So       |
|o* .   ..        |
|..* ..+.         |
|.. o.  o         |
|   .o .          |
+----[SHA256]-----+

이런 메세지가 뜨면서 파일 두개가 생성된다.
my_key와 my_key.pub이 생성되는데 .pub가 공개키, my_key 암호키 즉 쌍(pair)으로 생성된다.

생성한 키페어를 테라폼 파일에 등록한다.

# ec2.tf
resource "aws_key_pair" "ec2_key" {
    key_name = "my_key"
  public_key = "my_key.pub 안에 있는 내용 전부 붙여넣기" or file("./my_key.pub")
}

ec2.tf를 만들어 주고 위의 코드를 작성해서 생성한 키페어를 테라폼에서 사용할 수 있게 만들어준다.

ec2 생성

aws_instance를 사용해서 쉽게 생성할 수 있다.

#ec2.tf

resource "aws_instance" "real_ec2" {
    ami = "ami-0ba5cd124d7a79612"
    #ubuntu 20.04의 ami
    instance_type = "t3.small"
    security_groups = [aws_security_group.realPublicSG.id]
    subnet_id = aws_subnet.realPublicSubnet.id
    key_name = aws_key_pair.ec2_key.key_name
    root_block_device { #볼륨 설정 가능
            volume_size = 200
            volume_type = "gp3"
    }
    tags ={ #이름 설정 가능
            Name = "real_ec2"
    }
}
  • 인스턴스 타입을 설정할 수 있다.
  • ami의 경우 콘솔에서 ami검색을 통해 id를 확인할 수 있다.

작성완료 했으면 terraform plan 후 apply
(apply는 실제 환경에 적용이기 때문에 자주하지 않더라고 plan은 자주해서 오류를 바로바로 잡아내자!)

RDS 생성

rds.tf 파일을 생성한 후 아래와 같이 작성한다.

#rds.tf

#rds의 서브넷 그룹으로 사용할 subnet들 미리 지정
resource "aws_db_subnet_group" "realDBSubnetGroup" {
  name = "test"
  subnet_ids = [
    aws_subnet.realPrivateSubnet1.id,
    aws_subnet.realPrivateSubnet2.id,
    aws_subnet.realPublicSubnet.id,
  ]
  tags = {
    "Name" = "real-db-subnet-group"
  }
}

resource "aws_db_instance" "real_rds" { 
    allocated_storage = 50
    max_allocated_storage = 80
    skip_final_snapshot = true
    vpc_security_group_ids = [aws_security_group.realPrivateSG.id ]
        #보안그룹 지정.
    db_subnet_group_name = aws_db_subnet_group.realDBSubnetGroup.name
        #서브넷 그룹 지정.
    publicly_accessible = true
    engine = "mariadb"
    engine_version = "10.6.8"
    instance_class = "db.t3.small"
    db_name = "testDB"
    username = "admin"
    password = "testtest"
    tags = {
        "Name" = "realDB"
    }
}

생성완료 후 terraform plan 후 apply로 적용을 한다.

구성도

이런 형태로 구축하려고 한다.

서브넷 추가하기

#vpc.tf
#퍼블릭 서브넷
resource "aws_subnet" "realPublicSubnet" {
    vpc_id = aws_vpc.realVPC.id
    cidr_block = "10.0.0.0/24"
    availability_zone = "ap-northeast-2c"
    tags = {
        Name = "real-public-subnet"
    }
}
#프라이빗 서브넷
resource "aws_subnet" "realPrivateSubnet1" {
    vpc_id = aws_vpc.realVPC.id
    cidr_block = "10.0.1.0/24"
    availability_zone = "ap-northeast-2c"
    tags = {
        Name ="real-private-subnet1"
    }
}
resource "aws_subnet" "realPrivateSubnet2" {
    vpc_id = aws_vpc.realVPC.id
    cidr_block = "10.0.2.0/24"
    availability_zone = "ap-northeast-2a"
    tags = {
        Name = "real-private-subnet2"
    }
}
  • vpc_id 부분에 바로전에 만들었던 vpc의 id를 추가하면 쉽게 서브넷을 추가할 수 있다.
  • 아까 만들었던 이름을 사용해서 id를 쉽게 얻을 수 있다. (aws_vpc.testVPC.id)

IGW (인터넷 게이트웨이 추가)

# vpc.tf
resource "aws_internet_gateway" "realIGW" {
    vpc_id = aws_vpc.realVPC.id
    tags = {
        Name="real-IGW"
    }
}
  • vpc에서 외부와 통신할 수 있게 public subnet과 통신한 인터넷 게이트웨이를 추가한다.

라우팅 테이블 작성

#vpc.tf
##라우팅 테이블 만들기
#퍼블릭 라우팅 테이블
resource "aws_route_table" "realPublicRoute" {
    vpc_id = aws_vpc.realVPC.id
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = aws_internet_gateway.realIGW.id 
            #퍼블릭 서브넷에 인터넷 게이트웨이 연결.
    }
    tags = {
    Name = "real-public-route"
    }
}
#프라이빗 라우팅 테이블
resource "aws_route_table" "realPrivateRoute" {
    vpc_id = aws_vpc.realVPC.id
    tags = {
        Name = "real-private-route"
    }
}

#퍼블릭 라우팅 테이블 연결
resource "aws_route_table_association" "realPublicRTAssociation"{
    subnet_id = aws_subnet.realPublicSubnet.id
    route_table_id = aws_route_table.realPublicRoute.id
}

#프라이빗 라우팅 테이블 연결
resource "aws_route_table_association" "realPrivateRTAssociation1"{
    subnet_id = aws_subnet.realPrivateSubnet1.id
    route_table_id = aws_route_table.realPrivateRoute.id
}
resource "aws_route_table_association" "realPrivateRTAssociation2"{
    subnet_id = aws_subnet.realPrivateSubnet2.id
    route_table_id = aws_route_table.realPrivateRoute.id
}
  • 다음으로는 라우팅 테이블을 만들어 서브넷과 연결시켜준다.

보안그룹 생성

#vpc.tf
#퍼블릭 보안 그룹
resource "aws_security_group" "realPublicSG" {
    vpc_id = aws_vpc.realVPC.id
    name = "real public SG"
    description = "real public SG"
    tags = {
        Name = "real pulbic SG"
    }

}
#퍼블릭 보안 그룹 규칙
resource "aws_security_group_rule" "realPublicSGRulesHTTPingress" {
    type = "ingress"
    from_port = 80
    to_port=80
    protocol = "TCP"
    cidr_blocks = ["0.0.0.0/0"]
    security_group_id = aws_security_group.realPublicSG.id
    lifecycle{
        create_before_destroy = true
    }
}
resource "aws_security_group_rule" "realPublicSGRulesSSHingress" {
    type = "ingress"
    from_port = 22
    to_port= 22
    protocol = "TCP"
    cidr_blocks=["0.0.0.0/0"]
    security_group_id = aws_security_group.realPublicSG.id
    lifecycle{
        create_before_destroy = true
    }
}
resource "aws_security_group_rule" "realPublicSGRulesALLegress" {
    type = "egress"
    from_port = 0
    to_port= 0
    protocol = "ALL"
    cidr_blocks=["0.0.0.0/0"]
    security_group_id = aws_security_group.realPublicSG.id
    lifecycle{
        create_before_destroy = true
    }
}
#프라이빗 보안 그룹
resource "aws_security_group" "realPrivateSG" {
    vpc_id = aws_vpc.realVPC.id
    name = "real private SG"
    description = "real private SG"
    tags = {
        Name = "real private SG"
    }
}
#프라이빗 보안 그룹 규칙
resource "aws_security_group_rule" "realPrivateSGRulesRDSingress" {
    type = "ingress"
    from_port = 3306
    to_port=3306
    protocol = "TCP"
    security_group_id = aws_security_group.realPrivateSG.id
    source_security_group_id = aws_security_group.realPublicSG.id
    lifecycle{
        create_before_destroy = true
    }
}
resource "aws_security_group_rule" "realPrivateSGRulesRDSegress" {
    type = "egress"
    from_port = 3306
    to_port= 3306
    protocol = "TCP"
    security_group_id = aws_security_group.realPrivateSG.id
    source_security_group_id = aws_security_group.realPublicSG.id
    lifecycle{
        create_before_destroy = true
    }
}
  • public, private subnet의 보안그룹을 생성해준다.

    • public의 경우 ssh접속을 위한 22번 포트와, http 통신을 위한 80를 ingress로, 열어주고 외부로 나가는 egress는 모든 트래픽을 열어준다.
    • private의 경우 rds를 연결하기 위해 3306포트를 열어준다.
  • 테라폼에서는 보안 그룹을 설정할 때 인라인으로 규칙을 추가해주거나 aws_security_group_rule
    으로 추가할 수 있음.

  • 만약 인라인으로 지정하게 된다면 한 보안 그룹에서 인바운드로 허용하는 액세스원이 다른 보안 그룹인 경우 이를 지정 할 수 없다.
    => aws_security_group_rule를 사용해서 추가해주자.

  • ingress는 외부에서 내부로 들어오는 트래픽, egress는 내부에서 외부로 나가는 트래픽을 의미.

계획 및 적용

$ terraform plan
.
.
.
Plan: 16 to add, 0 to change, 0 to destroy.
$ terraform apply

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_security_group.testPrivateSG: Creating...
aws_route_table.testPrivateRoute2: Creating...
aws_route_table.testPrivateRoute1: Creating...
aws_route_table.testPublicRoute: Creating...
aws_security_group.testPublicSG: Creating...
aws_route_table.testPrivateRoute2: Creation complete after 1s [id=rtb-01a08a475c7aa3b6e]
aws_route_table_association.testPrivateRTAssociation2: Creating...
aws_route_table.testPrivateRoute1: Creation complete after 1s [id=rtb-0de978f9daf7138da]
aws_route_table_association.testPrivateRTAssociation1: Creating...
aws_route_table_association.testPrivateRTAssociation2: Creation complete after 0s [id=rtbassoc-04c687539b690b97e]
aws_route_table_association.testPrivateRTAssociation1: Creation complete after 0s [id=rtbassoc-00c81afb4d66a4afb]
aws_route_table.testPublicRoute: Creation complete after 1s [id=rtb-0b21780b54c48f288]
aws_route_table_association.testPublicRTAssociation: Creating...
aws_route_table_association.testPublicRTAssociation: Creation complete after 1s [id=rtbassoc-015a0b583a70d3d07]
aws_security_group.testPrivateSG: Creation complete after 2s [id=sg-0564ca6903f5d71ae]
aws_security_group.testPublicSG: Creation complete after 2s [id=sg-0d17e51c8f54212ee]
aws_security_group_rule.testPublicSGRulesHTTPegress: Creating...
aws_security_group_rule.testPrivateSGRulesRDSegress: Creating...
aws_security_group_rule.testPublicSGRulesHTTPSingress: Creating...
aws_security_group_rule.testPublicSGRulesHTTPSegress: Creating...
aws_security_group_rule.testPublicSGRulesHTTPingress: Creating...
aws_security_group_rule.testPublicSGRulesSSHegress: Creating...
aws_security_group_rule.testPrivateSGRulesRDSingress: Creating...
aws_security_group_rule.testPublicSGRulesSSHingress: Creating...
aws_security_group_rule.testPublicSGRulesSSHegress: Creation complete after 1s [id=sgrule-1099277773]
aws_security_group_rule.testPrivateSGRulesRDSegress: Creation complete after 1s [id=sgrule-640893485]
aws_security_group_rule.testPublicSGRulesHTTPSingress: Creation complete after 1s [id=sgrule-1338266698]
aws_security_group_rule.testPrivateSGRulesRDSingress: Creation complete after 1s [id=sgrule-3779608258]
aws_security_group_rule.testPublicSGRulesHTTPingress: Creation complete after 2s [id=sgrule-768399379]
aws_security_group_rule.testPublicSGRulesHTTPSegress: Creation complete after 2s [id=sgrule-292654581]
aws_security_group_rule.testPublicSGRulesSSHingress: Creation complete after 3s [id=sgrule-1743733607]
aws_security_group_rule.testPublicSGRulesHTTPegress: Creation complete after 3s [id=sgrule-3303017385]

Apply complete! Resources: 16 added, 0 changed, 0 destroyed.

이런식으로 적용이 완료 되면 성공이다.

+ Recent posts