안녕하세요, heyjee 입니다.

리눅스 쉘 스크립트 첫 순서로 awk(오크) command를 사용해서 간단한 user management book을 구현하는 쉘 스크립트를 작성해보겠습니다.

 

Linux awk란?

원래는 Unix에서 처음 개발된 일반 스크립트 언어로, 텍스트 형태의 입력 데이터를 행(row)과 단어(word)별로 처리해 출력합니다. (패턴처리언어?라고도 할 수 있을거같네요?)

 

현 리눅스 배포판에 의해, /bin/sh와 /bin/bash 모두 사용 가능함을 알려주고 있는 것 한번 확인해보고 넘어가겠습니다.

/bin/sh -> bash

 

작업해볼 디렉토리 하나 생성 후, 아래와 같이 두 파일을 vi 편집기를 통해 작성해줍니다.

 

info.txt

1,user1,010-1234-5678,user1@gmail.com,Seoul
2,user2,010-1111-2222,user2@gmail.com,Busan
3,user3,010-9876-5432,user3@gmail.com,Jeonju

 

awk-user-management.sh

#!/bin/sh
/bin/awk \
'BEGIN {FS=",";print "User Management"} \
{idx=$1}{name=$2}{phonenumber=$3}{email=$4}{location=$5} \
{num+=1} \
{print "[" idx "] " name "} \
{print "Mobile Phone Number : " phonenumber} \
{print "E-mail : " email} \
END {print "Total " num " users in here!"}' info.txt
Line 3 ~ 9 구문 처리 코드 전체를 '' (작은따옴표) 로 wrapping 
Line 3 : FS = Field Seperator 로, 처리할 텍스트의 word를 구분하는 일종의 delimeter 개념
Line 4 : FS에 의해 구분된 word 들을 각각의 쉘 변수에 차례대로 매핑
Line 5 : 총 인원수를 출력하기 위해 매 loop마다 출력 전 카운팅 시작

 

 

이렇게 작성한 후, 해당 쉘파일을 실행시키니... 아래와 같이 권한 에러가 발생합니다.

권한 에러 발생

혹시, root 권한에서 실행을 안시켜서 그런가하고 먼저 관리자 권한으로 실행해봤지만 역시나 될리가 없네요... (애초에 root 상에는 해당 파일들이 전무하니...)

 

그 다음 방법으로는 파일 자체의 권한을 살펴보기로 했습니다.

awk-user-management.sh 파일에 대해 실행 권한 (x) 가 부여되어 있지 않는 것을 확인했습니다.그렇다면, 해당 파일에 실행 권한만 부여해주면 실행이 되겠네요 ~

 

chmod 명령어로 700을 부여하고 확인해보니 x 권한이 부여된 것을 확인했습니다.

700으로 권한 부여

 

변경된 권한에 대해 다시 쉘파일을 실행시켜보니 정상적으로 출력하는 것을 확인할 수 있었습니다.

 

 

혹시 수정이 되어야 할 부분이 있다면 얼마든지 코멘트 대환영입니다 . 감사합니다 :)

안녕하세요, heyjee 입니다 .

React 첫 순서로, React Framework 와 Express Server 사이에서 프록시를 설정해보겠습니다 .

 

cf) 프록시(Proxy)란?

> 서버와 클라이언트 (또는 또다른 서버)사이에서 중계 역할을 하는 것입니다 .

사실, 프록시 없이도 서버간 통신하는데에는 아~무런 문제가 되지는 않습니다 .

다만, 프록시를 사용하는 목적은 뭐니뭐니해도 '보안' 이게 가장 클 것입니다 . IP 를 우회하는 개념을 가지고 있다보니 말이죠 ~

 

예를 들어볼까요?

React Framework 는 port 3000번으로, Express Server 는 port 3001번으로 통신하고 있다고 가정해봅시다 .

이때, http://localhost:3000/api/getAllTrainsInfo 의 경로를 가진 API 를 요청하면 프록시를 통해 http://localhost:3001/api/getAllTrainsInfo 의 경로로 호출하게 됩니다 .

달리 말해서, 서로 다른 두 서버가 마치 하나의 서버처럼 작동하게 해주는 것이 바로 프록시 입니다 .

 

React 프로젝트에서 이러한 프록시를 설정하는 방법으로는 setupProxy 스크립트 파일을 생성해 주는 것이 있습니다 .

위에서 예를 들어본 것으로 프록시를 설정해보겠습니다 .

 

 

먼저, 프록시 설정을 위해 React 프로젝트 경로에 다음과 같은 모듈을 설치해줍니다 .

 

설치 후, 프로젝트 src 디렉토리의 바로 하위 경로에 프록시 스크립트 파일을 생성합니다 .

/src/setupProxy.js

 

setupProxy.js 

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app){
  app.use(
      createProxyMiddleware('/api', {
          target: 'http://localhost:3001',
          changeOrigin: true
      })
  )
};
 Line 4 ~ 9 : app.use() 를 사용해 http-proxy-middleware 를 app 오브젝트 인스턴스에 바인딩
 Line 5 : createProxyMiddleware()의 첫번째 파라미터로 '/api' string 할당 . 호스트 하위 경로가 '/api' 로 시작하는 모든 요청에 대해 프록시 경유  (e.g. http://localhost:3000/api/getAllTrainsInfo 로 요청 > 프록시 경유)
 Line 6 ~ 7 : createProxyMiddleware 메소드의 두번째 파라미터로 다음과 같은 프로퍼티를 가지는 오브젝트를 할당 .
 첫번째 프로퍼티인 target string : 들어온 요청은 할당된 target string 을 통해 호출됨 (중요)
 두번째 프로퍼티인 changeOrigin 은 boolean value 를 가지며, 대상 서버의 구성에 따라 호스트 헤더를 변경해주는 옵션

 

원래 API 호출은 port 3001번을 통해서만 액세스가 가능하므로 port 3000번에 대해서 요청을 주면 에러가 발생하게 되지만,

이렇게 프록시 설정 후 port 3000번을 통해 API 요청을 주면, http://localhost:3001/getAllTrainsData 로 호출하게 되어 정상 호출 결과를 얻게 됩니다 .

 

 

혹시 수정이 되어야 할 부분이 있다면 얼마든지 코멘트 대환영입니다 . 감사합니다 :)

안녕하세요, heyjee 입니다 .

두번째 순서로 AWS SDK 를 활용해 보안그룹 (Security Group) 제어 메소드들을 구현해 보도록 하겠습니다 .

 

SDK 를 활용한 AWS 보안그룹 제어 소스는 공통 > utils 디렉토리에서 관리하는 것으로 하겠습니다 .

/common/utils/AwsSecurityGroup.java

 

총 6 개의 메소드를 구현해 보았습니다 .

 > 보안그룹 추가
 > 보안그룹 삭제
 > 인바운드 룰 추가
 > 인바운드 룰 삭제
 > 보안그룹 가져오기
 > IP Permission 객체 생성

주의할 점은 보안그룹의 인바운드 룰을 제어 (추가[add], 삭제[revoke])하는 메소드를 정의할 때,

IP 포트와 주소 정보 등을 setIpPermission 메소드를 통해 IpPermission 타입으로 객체화 후, 이를 request 객체에 담아 response 를 리턴해야 한다는 점입니다 .

 

작성해본 코드는 다음과 같습니다 

package com.common.utils;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;

@Slf4j
@Component
public class AwsSecurityGroup {

   private static final String SECURITY_GROUP_REGION = "";
   private static final String SECURITY_GROUP_ID = "";
   private static final String AWS_ACCESS_KEY = "";
   private static final String AWS_SECRET_KEY = "";
   private static final AmazonEC2 EC2 = AmazonEC2Client.builder()
           .withRegion(SECURITY_GROUP_REGION)
           .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY)))
           .build();

   public void addSecurityGroup (String groupName, String groupDescription, String vpcId) {
   
       try {
           // Request
           CreateSecurityGroupRequest request = new CreateSecurityGroupRequest()
                   .withGroupName(groupName)
                   .withDescription(groupDescription)
                   .withVpcId(vpcId);
                   
           // Result
           CreateSecurityGroupResult result = EC2.createSecurityGroup(request);
           log.info("##### CreateSecurityGroupResult : " + result.getSdkResponseMetadata());
       } catch (Exception e) {
           e.printStackTrace();
       }
       
   }

   public void deleteSecurityGroup (String groupId) {
   
       try {
           // Request
           DeleteSecurityGroupRequest request = new DeleteSecurityGroupRequest()
                   .withGroupId(groupId);
                   
           // Result
           DeleteSecurityGroupResult result = EC2.deleteSecurityGroup(request);
           log.info("##### DeleteSecurityGroupResult : " + result.getSdkResponseMetadata());
       } catch (Exception e) {
           e.printStackTrace();
       }
       
   }

   public void addInboundRule (String ipProtocolType, Integer toPort, Integer fromPort, String ipAddress) {
   
       try {
           // Request
           AuthorizeSecurityGroupIngressRequest request = new AuthorizeSecurityGroupIngressRequest()
                   .withGroupId(SECURITY_GROUP_ID)
                   .withIpPermissions(setIpPermission(ipProtocolType, toPort, fromPort, ipAddress));
                   
           // Result
           AuthorizeSecurityGroupIngressResult result = EC2.authorizeSecurityGroupIngress(request);
           log.info("##### AuthorizeSecurityGroupIngressResult : " + result.getSdkResponseMetadata());
       } catch (Exception e) {
           e.printStackTrace();
       }
       
   }

   public void revokeInboundRule (String ipProtocolType, Integer toPort, Integer fromPort, String ipAddress) {
   
       try {
           // Request
           RevokeSecurityGroupIngressRequest request = new RevokeSecurityGroupIngressRequest()
                   .withGroupId(SECURITY_GROUP_ID)
                   .withIpPermissions(setIpPermission(ipProtocolType, toPort, fromPort, ipAddress));
                   
           // Result
           RevokeSecurityGroupIngressResult result = EC2.revokeSecurityGroupIngress(request);
           log.info("##### RevokeSecurityGroupIngressResult : " + result.getSdkResponseMetadata());
       } catch (Exception e) {
           e.printStackTrace();
       }
       
   }

   public List<SecurityGroup> describeSecurityGroup (String groupId) {
   
       DescribeSecurityGroupsRequest request;
       DescribeSecurityGroupsResult result = new DescribeSecurityGroupsResult();
       
       try {
           // Request
           request = new DescribeSecurityGroupsRequest();
           if(!"all".equals(groupId)) {
               request = request.withGroupIds(groupId);
               }
           
           // Result
           result = EC2.describeSecurityGroups(request);
       } catch (Exception e) {
           e.printStackTrace();
       }
       
       return result.getSecurityGroups();
   
   }

   private static IpPermission setIpPermission (String ipProtocolType, Integer toPort, Integer fromPort, String ipAddress) {
       
       return new IpPermission().withIpProtocol(ipProtocolType)
               .withToPort(toPort)
               .withFromPort(fromPort)
               .withIpv4Ranges(new IpRange().withCidrIp(ipAddress + "/32"));
   
   }
}
 Line 5 ~ 7 : AWS Security Group 관련 클래스를 사용하기 위한 util 패키지
 Line 16 : EC2 의 리전 정의 (e.g. eu-central-1)
 Line 17 : 인바운드 룰을 추가 or 삭제할 대상의 특정 보안그룹 ID 정의 (e.g. sg-XXXXXXXXXXXX)
 Line 20 ~ 23 : 보안그룹 제어 대상 EC2 의 Configuration (리전, 인증) 정의
 Line 25 ~ 41 : 보안그룹 추가
 Line 43 ~ 57 : 보안그룹 삭제
 Line 59 ~ 74 : 지정된 보안그룹 (Line 17)에 Inbound Rule 추가
 Line 76 ~ 91 : 지정된 보안그룹 (Line 17)의 Inbound Rule 취소
 Line 93 ~ 113 : 보안그룹 목록 가져오기
 Line 101 ~ 103 : 특정 보안그룹 정보만 가져오기 위한 조건문
 Line 115 ~ 122 : IP 정보 객체 생성
 Line 120 : CIDR 값을 32 로 하드코딩

 

혹시 수정이 되어야 할 부분이 있다면 얼마든지 코멘트 대환영입니다 . 감사합니다 :)

'Java' 카테고리의 다른 글

1. Apply @Transactional Annotation in Spring Framework  (0) 2021.11.28

안녕하세요, heyjee 입니다 .

첫 순서로 Spring Framework 에서 서비스로직에 트랜잭션 어노테이션을 적용하는 방법을 알아보겠습니다 .

 

트랜잭션의 포인트는 모두 처리하면 성공 - 그렇지 않으면 실패  입니다 .

이 포인트를 적용해 작성해본 코드는 다음과 같습니다 .

@Service
public class UserMgmtSvc {

    @Autowired
    UserMgmtMapper userMgmtMapper;

    @Transactional(rollbackFor = { Exception.class })
    public void removeLongTermNoUseUserInfo (String guid) throws Exception {
        try {
            userMgmtMapper.deleteUserInfo(guid);
            userMgmtMapper.deleteUserRegionAuthority(guid);
            userMgmtMapper.deleteUserServiceAuthority(guid);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception();
        }
    }

}
 Line 7 : Transactional 어노테이션을 선언해줌으로써 removeLongTermNoUseUserInfo 메소드를 트랜잭션으로 처리
 이 때, rollbackFor 속성을 추가함으로써 트랜잭션 실행 중 어떠한 Exception 이라도 발생한다면 진행중인 트랜잭션을 취소하고 롤백
 Line 9 ~ 16 : 세 개의 mapper 메소드 트랜잭션 처리에 대해 try-catch 구문을 적용
 Line 15 : 발생한 Exception 을 catch 할 때, 명시적으로 해당 Exception 을 throw 처리 (중요)
 > 해당 구문이 없으면 트랜잭션 처리 중 Exception 발생 시, 롤백을 실패하게 됨

 

혹시 수정이 되어야 할 부분이 있다면 얼마든지 코멘트 대환영입니다 . 감사합니다 :)

'Java' 카테고리의 다른 글

2. Implement AWS Security Group control methods using SDK  (0) 2021.12.04

안녕하세요, heyjee 입니다 .

이번에는 AWS 대시보드에서 EKS 클러스터 및 노드를 직접 생성해보기로 하겠습니다 .

 

그전에, 다음의 네 가지 tool 을 install 및 apply 가 필요합니다 .

 > AWS CLI
 > aws configure 을 통한 IAM
 > kubectl
 > eksctl

 

여기서 kubectl 과 eksctl 의 차이점은 ...

 kubectl : k8s 클러스터 작업을 위한 명령줄 tool
 eksctl : 개벌 태스크를 자동화하는 EKS 클러스터를 사용하기 위한 명령줄 tool

 

install 및 apply 가 완료되었다면, 본격적으로 생성해보도록 하겠습니다 .

 

1. EKS 클러스터용 Role 을 생성합니다 .

2. EKS 노드그룹용 Role 을 생성합니다 .

 

3. 심플한 VPC 환경 구성을 위해 CloudFormation 으로 스택을 생성합니다 .

 

4. 본격적으로 다음과 같이 EKS 클러스터를 구성합니다 .

(이 때, 서브넷은 2개의 private subnet 으로 설정합니다 .)

 

5. 생성 및 활성화된 클러스터를 확인합니다 . 

 

6. (AWS CLI, kubectl 사전 Install 후)

'kubectl get pod --all-namespaces' 명령어를 통해 클러스터가 생성되었는지 확인합니다 .

> 현재 생성되어 있는 coredns ~ 이름의 클러스터 2개의 status 가 Pending (보류중) 상태입니다 .
이것은 클러스터만 생성했을 뿐, 아직 그 안에 노드를 생성하지 않았기 때문입니다 .
따라서, 노드도 생성을 해주어야 합니다 .

 

 

7. 클러스터 안에 들어갈 노드 그룹을 구성합니다 .

(마찬가지로, 서브넷은 2개의 private subnet 으로 설정합니다 .)

8. 원하는 개수만큼의 노드가 생성 및 활성화되었는지 확인합니다 . 

 

9. 다시 'kubectl get pod --all-namespaces' 명령어를 통해 노드가 생성되었는지 확인합니다 .

kube-system 네임스페이스 안에 aws-node ~ 이름의 노드 2개와 각 노드에 대한 kube-proxy Static Pod 가 생성되어 클러스터의 status 가 Running 상태로 바뀐 것을 확인할 수 있습니다 .

이렇게 생성된 해당 노드에 ssh 접속하여 각종 k8s 리소스 생성을 통한 아키텍처 구축 진행이 가능합니다 .

 

여기까지가 AWS 대시보드를 통한 단일 클러스터 생성 과정이었습니다 .

당연한 말이겠지만, 단일 뿐만 아니라 멀티 클러스터 생성 및 구축도 가능합니다 .

(예를 들면, 배포 환경 setting 시, DEV / STG/ PRD 각각에 서로 다른 클러스터로 구축)

 

한 가지 또 말씀드리고 싶은 것은, 맨 위에서 언급한 eksctl 을 설치했다면 해당 명령어에 의한 imperative command 방식으로 일련의 작업이 가능합니다 . 실무에서는 eksctl 을 통해 구축 작업이 이루어진다고 선배님께서 말씀해주시기도 하셨네요 ~

그래서 !!! 다음 3편에서는 eksctl 명령어를 통한 기본 구축을 한 번 해보도록 하겠습니다 .

 

혹시 수정이 되어야 할 부분이 있다면 얼마든지 코멘트 대환영입니다 . 감사합니다 :)

'AWS' 카테고리의 다른 글

1. What is EKS (Elastic Kubernetes Service) ?  (0) 2021.11.27

안녕하세요, heyjee 입니다 .

k8s 를 공부하면서 이런 생각을 해봤습니다 .

'아키텍처가 작으면 괜찮겠지만, 만약 전사적으로 큰 규모의 아키텍처라면 클러스터 및 노드를 포함한 각종 리소스를 일일이 생성하고 관리하기가 매우 까다롭고 번거로울 수 있을 것 같다 .'

그래서 알아보니 AWS 에서 EKS 라는 서비스를 제공한다고 해서 Intro 부터 알아보기로 했습니다 .

 

먼저, EKS 를 다음과 같이 정리할 수 있습니다 .

 EKS = Elastic Kubernetes Service

 > k8s 를 실행하는데 사용할 수 있는 관리형 서비스

 > AWS 의 여러 가용 영역 (Availability Zone) 에 걸쳐 k8s 에서 마스터 노드라 할 수 있는 control plane 을 실행하고 그 크기를 조정해서 높은 가용성을 보장

 > 컨테이너에 삽입되는 이미지에 대해 ECR, ELB, IAM, VPC 기능을 포함한 Application 에 대한 확장성과 보안까지 제공

 

위에서 control plane 이라는 일종의 마스터 노드?같은 이 친구에 대해서 좀 더 알아보면...

 EKS control plane 아키텍처

 > 각 클러스터에 대해 단일 테넌트의 k8s control plane 을 실행

 > control plane 은 2개 이상의 API 서버 인스턴스와 리전 내 3개의 가용 영역에서 실행되는 3개의 etcd 인스턴스로 구성

 > control plane 인프라는 클러스터 또는 AWS 계정간에 공유되지 않음 (각 클러스터마다 독립적)

 > EKS 는 VPC 네트워크 정책을 사용하여 control plane 구성 요소간의 트래픽을 단일 클러스터 내로 제한
 따라서, 클러스터에 대한 control plane 구성 요소는 k8s RBAC (Role Based Access Control) 정책에 따라 권한을 부여받지 않은 경우, 다른 클러스터 또는 다른 AWS 계정의 통신을 보거나 수신 불가 !

 

이러한 특징을 가진 EKS 의 Workflow 는 다음과 같이 총 4단계로 볼 수 있습니다 .

 

EKS Workflow

 1. Provision an EKS cluster : AWS Management Console, CLI, SDK 를 사용하여 EKS 생성
 2. Deploy compute : 관리형 / 자체 관리형 EC2 노드를 실행하거나 워크로드를 Fargate 에 배포
 3. Connect to EKS : 클러스터가 준비되면, 원하는 k8s 도구를 구성해 클러스터와 통신 가능
 4. Run Kubernetes application : EKS 클러스터에 워크로드 배포, 관리

 

다음 2편에서는 실제 AWS 대시보드에서 EKS 클러스터 및 노드를 생성하는 방법을 알아보기로 하겠습니다 .

 

혹시 수정이 되어야 할 부분이 있다면 얼마든지 코멘트 대환영입니다 . 감사합니다 :)

'AWS' 카테고리의 다른 글

2. Create EKS Cluster & Node with AWS Dashboard  (0) 2021.11.27

+ Recent posts