기본적인 SQL 문법을 다룬다. 예시만 적어두고 필요할 때 참고하기 위함


DML (Data Manipulation Language, 데이터 조작어)


SELECT

/*모든 데이터 조회*/
Select * from {table}

/*특정 데이터 조회 - 조건 설정*/
Select * from {table} where {column} {조건}

ex) Select * from Student where Name = 'JPK'

INSERT

/*테이블에 새로운 row 삽입*/
Insert Into {table} ({column1, column2, ...}) Values ({set value1, set value2, ...})

ex) Insert Into Student (Age, Name, Rank) Values (set 15, set 'ABC', set 4.5)

UPDATE

/*테이블에서 특정 값을 수정*/
Update {table} set {column} = '{new value}' where {column} = '{before value}'

ex) Update Student set Name = 'JPK2' where Name = 'JPK'

DELETE

/*특정 value 값을 가지고 있는 Column의 row를 삭제*/
Delete from {table} where {column} = '{value}'

ex)Delete from Student where Name = 'JPK'

DDL (Data Definition Language, 데이터 정의어


CREATE

/*테이블을 생성하는 쿼리*/
CREATE Table {table} ({column1} {type}, {column2} {type}, ...)

ex) CREATE Table Student (Age int, Name varchar(50), Rank Float)

ALTER

/*테이블을 수정하는 쿼리*/
ALTER Table {table} Add ({new column} {type} {type value})

ex) ALTER Table Student Add (Address varchar (100))

DROP

/*테이블 혹은 데이터베이스를 삭제하는 쿼리*/
DROP Table {table / Database}

/*테이블 삭제*/
ex) DROP Table Student

/*데이터베이스 삭제*/
ex) DROP Database School

TRUNCATE

/*데이터를 자르기 하는 쿼리*/
/*테이블을 남겨두지만 테이블 내 모든 row를 비워버린다.*/
/*한 번 자르면 복구가 불가능하다. 데이터 뿐만 아니라 공간과 인덱스까지 삭제하기 때문*/
/*로그를 남기지 않기 때문에 속도가 빠르다.*/
DROP Table {table / Database}

ex) Truncate Table Student

DCL (Data Control Language, 데이터 제어어)


GRANT

/*데이터베이스 객체에 대한 특정 권한을 사용자에게 부여한다.*/
GRANT {QUERY COMMANDS} ON {table} TO {user}

/*user10에게 select, insert, delete 권한을 준다.*/
ex) GRANT SELECT, INSERT, DELETE ON Student TO user10

/*데이터베이스 객체에 대한 특정 권한을 사용자에게 부여한다.*/
GRANT {QUERY COMMANDS} ON {table} TO {user}

/*user10에게 select, insert, delete 권한을 준다.*/ 
ex) GRANT SELECT, INSERT, DELETE ON Student TO user10

REVOKE

/*데이터베이스 객체에 대한 특정 권한을 사용자에게 취소한다.*/
REVOKE {QUERY COMMANDS} ON {table} TO {user}

/*user10에게 select, insert, delete 권한을 취소한다.*/
ex) REVOKE SELECT, INSERT, DELETE ON Student TO user10

TCL(Transaction Control Language , 트랜잭션 제어어)


COMMIT

/*트랜잭션(작업 단위)에 이상이 없을 때 commit하는 쿼리이다.*/
ex) 
/*트랜잭션 시작을 알린다.*/
BEGIN TRAN (or TRANSACTION)

/*필요한 쿼리문을 수행한다. 이 때 변경된 사항은 메모리에만 저장된다*/
UPDATE Student set Name = 'JPPPPK' where Name = 'JPK'

/*쿼리문에 문제가 없다면 COMMIT을 통해 DB 혹은 디스크에 저장한다.*/
COMMIT TRAN

ROLLBACK

/*트랜잭션 실행에 이상이 있을 때 데이터를 원복하는 쿼리이다.*/
/*트랜잭션이 이미 커밋되었다면(디스크에 등재되었다면) 실행할 수 없다.*/

ex) 
/*트랜잭션 시작을 알린다.*/
BEGIN TRAN (or TRANSACTION)

/*BookCount라는 int type을 가진 변수를 정의한다.*/
DECLARE @BookCount int

/*AddBook이라는 이름의 트랜잭션을 시작한다.*/
BEGIN TRANSACTION AddBook

/*Books 테이블에 아래와 같은 Values를 가진 row를 생성한다.*/
INSERT INTO Books VALUES (20, 'Book15', 'Author1', 3000)

/*Books 테이블에서 책 이름이 Book15라는 이름을 가진 데이터들을 집계한다.*/
SELECT @BookCount = COUNT(*) FROM Books WHERE name = 'Book15'

/*만약 동일한 이름의 책이 2권 이상 발견되었다면 AddBook 트랜잭션을 ROLLBACK하여, 디스크에 등재하지 않고 작업을 종료한다.*/
F @BookCount > 1 BEGIN ROLLBACK TRANSACTION AddBook PRINT 'A book with the same name already exists' END

/*그렇지 않다면 COMMIT하여 디스크에 등재시킨다.*/
ELSE BEGIN COMMIT TRANSACTION AddStudent PRINT 'New book added successfully' END 

SAVEPOINT

/*트랜잭션을 일시저장하여 필요한 지점으로 롤백할 수 있도록 하게 해준다.*/
/*SAVEPOINT 이름은 중복될 수 없으며 트랜잭션 작업 도중 문제가 생긴다면 작업이 돌아갈 지점을 설정하거나 전체 rollback, 작업이 성공한 지점까지의 commit 등 여러가지 작업이 가능하다.*/

ex)
/*AA의 급여는 7000원으로 업데이트한다.*/
UPDATE employees SET salary = 7000 WHERE last_name = 'AA';

/*BB의 급여는 12000원으로 업데이트한다.*/
UPDATE employees SET salary = 12000 WHERE last_name = 'BB';

/*이 시점에 SAVEPOINT AA를 저장한다.*/
SAVEPOINT AA;

/*이 시점에 SAVEPOINT BB를 저장한다.*/
SAVEPOINT BB;

/*급여의 총 금액을 구한다. 이 구문에는 없지만 어떤 조건에 의해 BB의 급여를 다시 설정해야하는 상황이 생겼다고 가정하자.*/
SELECT SUM (salary) FROM employees;

/*SAVEPOINT AA 시점으로 되돌아간다.*/
ROLLBACK TO SAVEPOINT AA;

/*BB의 급여를 11000원으로 업데이트한다.*/
UPDATE employees SET salary = 11000 WHERE lase_name = 'BB';

/*디스크에 등재한다.*/
COMMIT;

'Server > MSSQL' 카테고리의 다른 글

MSSQL Server / SSMS(SQL Server Management Studio) 설치하기  (0) 2024.08.25

프로그램 설치

MSSQL을 설치해보도록 하자
마이크로소프트 MSSQL 공식 홈페이지에 접속하면 MSSQL을 설치할 수 있다.

여기서 필자는 상업용이 아닌 공부용으로 사용할 목적이므로 개발자 버전 (SQL Server 2022 Developer)를 다운 받아 설치한다.
설치가 끝나면 SSMS를 같이 설치할 수 있도록 설치 버튼이 존재하며 쿼리를 작성해야하니 함께 설치해준다.

SSMS 연결

서버 설치 및 SSMS 설치가 완료되었다면 SSMS를 실행해 데이터 베이스를 생성할 차례이다.


만약 위 화면에서 [SSMS 연결 도중 신뢰되지 않은 기관에서 인증서 체인을 발급했습니다.] 와 같은 오류가 발생했다면

[추가 연결 매개 변수] 탭에서 "TrustServerCertificate=True" 값을 설정해준다.


로컬에서만 테스트할 목적으로 SSMS를 사용하기 때문에 위와 같은 설정으로 넘어가지만, 실 서비스에서는 설정을 잘 해줘야한다.

'Server > MSSQL' 카테고리의 다른 글

MSSQL 기초 문법  (0) 2024.08.25

들어가기에 앞서 필자는 노드 버전 v20.10.0을 사용하였으며
Next.js는 v14.0.4를 사용함

Next.js 설치

먼저 StyleX를 적용하기 위해 Next.js를 먼저 설치해준다.

npx create-next-app@latest .

그 다음부터는 공식문서를 보고 따라했다.
StyleX 설치 공식문서

StyleX 패키지 설치

npm install --save @stylexjs/stylex

위 명령어를 실행하여 StyleX에 대한 패키지를 설치해준다.
그리고 Babel을 별도로 설정해주어야 한다.

여기서 바벨이란?
=> 바벨은 크로스 브라우징 이슈를 최소화하기 위해 ES6+ 버전의 자바스크립트나 타입스크립트, JSX 문법 등을 모든 브라우저에서 호환 가능하도록 변환시켜주는 역할을 한다.
따라서, 크로스 브라우징 이슈와 밀접한 관계가 있는 프론트엔드 개발자에게 바벨 설정의 능력이 요구되고는 한다.

StyleX도 자신만의 표현을 브라우저가 알아들을 수 있게 번역(?)해줄 필요가 있는데 바벨 설정을 통해 해결할 수 있다.
현재 Rollup, Webpack 등 모듈 번들러에 대한 바벨 플러그인을 별도로 지원하는데,
맨 아래 보면 Next.js 전용으로 지원하는 플러그인이 존재해 이를 사용할 예정이다.

Babel Plugin 설정

공식문서에 따르면 babel.config.js 파일과 .babelrc.js 파일 두 가지를 제공하고 있는데
둘 다 바벨 설정이 가능한 파일이라 하나만 골라 쓰면 된다.

위에서 언급했듯이 필자는 Next.js 용으로 제공되는 .babelrc.js 설정을 통해 바벨 플러그인을 설정하였다.

npm install --save-dev @stylexjs/nextjs-plugin

먼저 패키지를 설치해주고 나서
.babelrc.js 파일을 작성한다.

//.babelrc.js
module.exports = {
  presets: ['next/babel'],
  plugins: [
    [
      '@stylexjs/babel-plugin',
      {
        dev: process.env.NODE_ENV === 'development',
        runtimeInjection: false,
        genConditionalClasses: true,
        treeshakeCompensation: true,
        unstable_moduleResolution: {
          type: 'commonJS',
          rootDir: __dirname,
        },
      },
    ],
  ],
};

그 다음 next.config.js 파일을 수정한다.

//next.config.js
const stylexPlugin = require('@stylexjs/nextjs-plugin');

module.exports = stylexPlugin({
  rootDir: __dirname,
})({});

여기까지만 설정해도 StyleX는 적용된다.

StyleX 코드 작성 및 실행

폴더 구조는 아래와 같으며 page.tsx에는 스타일을 확인하기 위한 코드를 작성했다.

여기서 하나 주의할 점이 있는데, app 디렉토리 하위에 globals.css는 layout.tsx에 import 되어있어야 한다.
(globals.css가 없으면 오류는 발생하지 않지만 스타일 적용이 되지 않는다… 이거 찾느라 5시간 정도 걸린 것 같다…!)

저 코드를 작성하고 npm run dev를 실행시키면 스타일이 잘 적용된 것을 볼 수 있다.

이전 포스트에서 처음에 StyleX를 소개하길 JS Object 형태로 스타일을 정의하나
서버 코드로 동작시킬 수 있다고 언급했었는데 크롬 설정에 자바스크립트를 꺼놓고 확인을 해보았다.


마무리

StyleX 설치 및 동작에 대해 알아보았다. 중간에 막히는 부분이 있었지만 다행히 다음 Step으로 넘어갈 수 있었다.
현재까지는 겉핥기 수준이라 좋은지 아닌지는 잘 모르겠다. StyleX에서 지원하는 강력한 기능들이 있는데 직접 써보고 별도 포스팅을 할 예정이다.

-끝

(혹시 제가 작성한 내용에 오류가 있어 수정이 필요한 부분을 친절히 알려주시면 정말 감사드리겠습니다…!)

'FrontEnd > StyleX' 카테고리의 다른 글

[StyleX] - Meta에서 제공하는 오픈소스 라이브러리  (0) 2024.01.05

Meta(Facebook)에서는 얼마 전 StyleX라는 명칭의 라이브러리를 오픈소스화 하여 제공하고 있다.
StyleX는 Meta 내부적으로 사용하던 스타일링 방식인데 소개 및 특징에 대해 다루고자 한다.

StyleX가 무엇일까?

우리는 보통 Web Frontend 페이지에 스타일을 적용할 때 Css를 사용한다. 그러나 차츰 JS 형태로 스타일링을 구현하는 형태를 사용하기 시작하였고 CSS-in-JS, Styled-Components 등이 대표적이다.

기존에 이런 훌륭한 기술들이 존재하는데 왜 또 StyleX라는게 나타나서 개발자들을 괴롭히는가?

아무리 좋은 라이브러리라고 해도 약점이 있기 때문이다.
때문에 기존 유명한 라이브러리들의 약점을 보완하며 장점들을 살릴 수 있는 새로운 기술이 지속적으로 개발되고 있다.

StyleX도 다르지 않다. CSS-in-JS와 유사한 형태로 사용자에게 익숙한 느낌을 주되, 여러가지 불편한 부분들에 대해 보완이 진행된 버전이라고 볼 수 있겠다.

StyleX의 특징

StyleX의 특징을 알아보자.
먼저 StyleX는 CSS-in-JS의 솔루션이다.

1. CSS-in-JS의 약점 극복

CSS-in-JS는 아래와 같은 약점을 가지고 있다.

  1. 같은 요소에 여러가지 스타일을 적용할 수 없다.
  2. 조건부 스타일을 사용할 수 없다.

Ex) css-in-JS의 형태

const styles={
	button: {
		background: 'red';
	},
	button2: {
		fontSize: 1rem;
	}
}

const button = () => <button style={styles.button}>Hello!</button>
// button에 이미 스타일이 적용되었기 때문에 button2는 적용 불가

이러한 제약은 서비스를 만들어낼 때 많은 불편함을 초래한다.
기본적으로 코드가 길어지고 인적, 시간적 비용이 자연스럽게 늘어나게 된다.

반면에 StyleX를 사용하면 위 문제들을 해소할 수 있다.

import * as stylex from '@stylexjs/stylex'
const styles = stylex.create({
	button: {
		background: 'red';
	},
	button2: {
		fontSize: 1rem;
	}
})

const button = () => <button {...stylex.props(
	styles.button,
	styles.button2,
	isActive && styles.active
)}>Hello!</button>

2. StyleX는 컴파일러다.

컴파일러 : 사람이 작성한 코드를 기계어로 번역하는 것

프로젝트를 빌드할 때 StyleX는 사용자가 정의한 스타일을 JS 객체로 가져와 이를 원자적 css로 변환한다.

import * as stylex from '@stylexjs/stylex'
const styles = stylex.create({
	button: {
		background: 'red';
	}
})

const button = () => <button {...stylex.props(styles.button)}>Hello!</button>

위와 같은 코드가 있을 때

const button = () => <button className="2cbc1xo">Hello!</button>

이와 같은 코드로 컴파일 한다.

기존 CSS-in-JS는 스타일 적용시 자바스크립트에 의존적이므로 속도가 느려질 수 있는데,
컴파일을 진행되면 렌더링 과정에서 style에 대한 자바스크립트 코드가 적용될 필요가 없어지므로 이를 개선할 수 있다.

그리고 필자는 아래와 같은 이유 때문에 StyleX을 공부하게 되었는데
바로 Next.js와 같은 서버 컴포넌트 사용시 JS 기반 스타일링을 사용하기 위함이다.

브라우저 렌더링 과정을 보면 HTML, CSS를 파싱하여 트리구조를 만들고 이후에 JS 코드를 적용하는데,
StyleX를 사용하면 스타일링에 대한 부분을 hydration하는 과정이 사라지기 때문에
JS 적용 이전에 스타일링이 적용된 화면을 제공할 수 있게 된다.

3. Type 안정성이 보장된다.

StyleX는 모든 css 스타일링에 대해 Type 지정이 내장되어있다.

예컨데 아래와 같을 수 있겠다.

type position = 'static' | 'relative' | 'absolute' | 'sticky' | 'fixed';

이러면 유저에게 명확한 속성을 제공하고, 오류가 발생했을 때 원인을 찾기 용이하다.


마무리

여러가지 특징이 더 존재하지만 앞서 소개한 세 가지가 대표적이라고 할 수 있을 것 같다.
이 정도만 봐도 StyleX는 정말 많은 것을 제공한다.
그렇지만 다른 라이브러리가 절대 약하다는게 아니다.
프로젝트 규모와 컨셉, 각 회사에 맞는 코드 컨벤션에 따라 어떤 Style 방식을 적용할지에 대해서는 답이 없다.

그래도 필자는 꼭 써볼 예정이다.
써보고 괜찮으면 주력 스킬로 가져가야지

'FrontEnd > StyleX' 카테고리의 다른 글

[StyleX] - Next.js에 StyleX를 적용해보자!  (2) 2024.01.11

CSR(Client Side Rendering)이란?

어떤 유저가 리액트로 제작된 어떤 웹사이트에 접속한다고 가정해보자.
유저는 바로 Client가 되는 것이고 웹 서버에 접속하려는 사이트를 요청한다.

서버에서는 요청을 받고 빈 HTML 파일을 우선 전송한다.
클라이언트의 화면에는 빈 HTML을 그리기 때문에 빈 화면이 나타나고, 뒤늦게 React 소스 코드와 개발자가 웹 페이지를 구현하기 위해 작성한 JS파일을 다운로드 받아 읽어내고, 그리고 마침내 화면에 그려낸다.

요약하자면 클라이언트의 요청에 따라 HTML, React 라이브러리 자체, 개발자가 구현한 소스 코드 등의 파일을 모두 다운로드 한 후 DOM을 구성하고 그려내 화면에 나타내는 것.
바로 이것이 Client Side Rendering이라고 할 수 있다.

CSR의 장점

  1. Client Side Rendering의 장점으로는 한번 로딩 되면, 빠른 UX를 제공한다.
  2. Client에 화면을 구성하는 대부분의 요소가 존재하기 때문에 서버의 부하가 그만큼 적다.

CSR의 단점

  1. 서버로부터 화면 구현에 필요한 요소를 받아와야 하기 때문에 페이지 로딩 시간 (Time To View)이 길다.
  2. 자바스크립트 활성화가 필수이다.
    사용자가 브라우저 설정을 통해 자바스크립트 활성화를 꺼버린다면 어떠한 페이지도 볼 수 없다.
  3. SEO 최적화가 힘들다.
    검색 엔진 로봇들이 웹사이트를 돌아다니며 메타 데이터 / Sementic Tag 등을 분석해 검색어와 연관 있는 요소들을 찾아 검색 엔진에 등록하는데, CSR의 경우 웹 페이지가 Client측에서 그려지고 나서야 이런 작업들이 가능하다.
  4. 보안에 취약하다.
    페이지를 표기하기 위해서 어떤 서버에서 어떤 데이터를 받아오는지 이런 불안 요소들이 외부에 노출 될 수 있다.
  5. CDN에 캐시가 안된다.
    Content Delivery Network의 약어로 각 국가나 지역에 있는 네트워크를 뜻한다.
    예를 들어 한국에서 미국으로 웹서버 요청을 전송 했을때, 도쿄 혹은 싱가포르 등 근처의 네트워크에 데이터를 캐싱할 수 있다.
    따라서 동일한 미국 서버에 여러번 접근 하더라도 근처에 이미 캐싱 된 데이터가 있기 때문에 응답이 빨라지는데,
    CSR에서는 HTML이 텅텅 비어있기 때문에 CDN에 캐싱하기 어렵다.

SSG (Static Site Generation)이란?

CSR이 처음에는 좋아보였지만, 앞선 포스팅에서 꽤나 비중 높은 단점들이 존재했고 이런 애로사항을 해소하고자 배포할때는 정적인 사이트로 전환해서 배포하는게 어떨까? 해서 나온게 SSG이다.

SSG의 특징

위에서 설명했듯이 렌더링 하는 주체자가 서버이다.
이후에 나타날 SSR과 동일하게 서버에서 렌더링을 하지만, 차이가 있다면 렌더링이 되는 시점이다.
SSG는 어플리케이션을 빌드할 때 렌더링한다.
빌드를 하는 과정에서 HTML에 React/JS 코드를 적용하고 필요하다면 클라우드나 DB에 있는 데이터를 fetch하여 정적인 웹페이지들을 미리 제작해둔다.

SSG의 장점

  1. 페이지 로딩 시간이 빠르다.
  2. 자바스크립트가 필요 없다.
  3. SEO 최적화가 좋다.
  4. 보안이 뛰어나다.
  5. CDN 캐시가 된다.

SSG의 단점

  1. build 시점에 렌더링이 되기 때문에 데이터가 정적이다.
    => 데이터가 가변적으로 변경되는 웹사이트의 경우 적절하지 않다. (예를 들면 실시간 날씨 정보 등등)
  2. 사용자별 정보 제공이 어렵다.
    => 사용자가 1,000명 10,000명이라면 그만큼의 정적 파일들을 미리 렌더링해야 한다.
    => 이런 경우 서버 부하가 심하다.

ISR (Incremental Static Regeneration)이란?

SR도 SSG와 마찬가지로 빌드 단계에서 정적인 html을 전부 만들어 놓는 것은 동일하지만 주기적으로 변경사항에 대응할 수 있도록 한 방식이다.

ISR의 특징

SSG의 특징을 전부 가지고 있으며 주기적으로 빌드를 하기 때문에 데이터 업데이트가 가능하다.

SSG의 장점

  1. 페이지 로딩 시간이 빠르다.
  2. 자바스크립트가 필요 없다.
  3. SEO 최적화가 좋다.
  4. 보안이 뛰어나다.
  5. CDN 캐시가 된다.
  6. 데이터가 주기적으로 업데이트 됨

SSG의 단점

  1. 데이터가 주기적으로 업데이트 되지만 이 또한 실시간 데이터가 아니다.
  2. 사용자별 정보 제공이 여전히 어렵다.

SSR (Server Side Rendering)이란?

SSR은 렌더링을 하는 주체가 서버이며, 클라이언트가 요청을 할 때마다 렌더링을 진행하는 특징이 있다.

SSR의 장점

  1. 페이지 로딩 시간이 빠르다.
  2. 자바스크립트가 필요 없다.
  3. SEO 최적화가 좋다.
  4. 보안이 뛰어나다.
  5. CDN 캐시가 된다.
  6. 실시가 데이터를 사용한다.

SSR의 단점

  1. SSG, ISR과 비교했을 때 상대적으로 느릴 수 있다.
  2. 클라이언트의 요청마다 서버에서 렌더링을 진행하기 때문에 부하가 굉장히 커질 수 있다.

마무리

CSR, SSG, ISR, SSR에 대해 간략하게 알아보았다.
각각의 장단점이 뚜렷하기 때문에 Next.js에서는 위 네 가지 방식을 적재적소 사용할 수 있도록 지원한다.

어플리케이션을 어떻게 구성하고 각 기능마다 어떤 렌더링 기법을 사용할 것인지 많은 고민이 있어야 사용자 경험이 좋은 페이지를 제작할 수 있을 것 같다.

'FrontEnd > Next.js' 카테고리의 다른 글

[Next.js] Next.js란?  (0) 2023.10.15

앞선 과정에서 Route53 서비스를 이용해 프로젝트에 도메인을 부여했다.
그러나 해당 도메인에 접근할 때 보니 http 즉, 보안성이 결여된 도메인이었다.

이제 해당 도메인을 https로 만들기 위해 ACM(AWS Certificate Manager)를 사용할 생각이다.

ACM이란?
웹 사이트와 애플리케이션을 보호하는 퍼블릭 및 프라이빗 SSL/TLS X.509 인증서와 키를 만들고, 저장하고, 갱신하는 복잡성을 처리.

이제 사용중인 ECS 서비스에 SSL을 적용해보고자 한다.

인증서 요청

먼저 인증서 요청 페이지에 접근하면 아래와 같은 화면이 나타난다.
퍼블릭 인증서 요청 선택한다.

그 다음 도메인 이름에는 [*.mydomain.com]
위와 같이 나의 도메인을 설정하는데, 맨 앞에 "*."을 붙여준다.


앞선 포스팅에서 서브 도메인을 생성했는데, sub.mydomain.com 이와 같은 형식이었다.
"*."을 붙여주게되면 mydomain 앞에 어떤 서브도메인명이 붙더라도 전부 인증서가 적용된다.

인증서가 생성되고 최초 상태는 검증 대기 중이다.

Route53 연결

[CNAME 이름 / CNAME 값]을 저장해두고 Route53에서 레코드 생성 버튼을 누른다.

그 다음 SSL 인증서 적용을 원하는 도메인을 클릭한 후 레코드를 생성한다.


이 상태로 Route53의 호스팅 영역에서 방금 체크한 도메인 호스팅 영역을 살펴보면
CNAME으로 레코드가 생성되어 있다.

잠시 기다리면 ACM 인증서가 발급 상태로 변경된다.(한 5분 걸리는 듯 하다.)

로드밸런서 리스너 추가

ACM은 로드밸런서를 통해서만 사용이 가능하다.


리스너 및 규칙 우측에 [리스너 추가] 버튼을 누른다.

프로토콜 HTTPS를 추가해주고, 대상 그룹을 지정한다.

다음 스텝으로 보안 정책을 선택하고
Certificate source => ACM으로 선택해준다.
그 후 Certificate => 구매한 도메인을 설정해준다.

잠시 기다리면 SSL/TLS가 적용된다.


도메인 맨 앞에 자물쇠 모양이 생겼으면 성공!

도메인 연결에 앞서 선행되어야 할 것들

  1. 도메인을 보유하고 있어야 한다.
  2. ELB 설정

AWS에서 도메인을 구매할 수 있지만, 연간 12~13 달러를 지불해야한다.
필자는 가비아에서 할인하는 도메인을 구매해 사용할 예정이다.

또한, 개인 도메인 접근은 로드밸런서를 통해 진행되도록 해볼 예정이다.

Route53 개인 도메인 연결


호스팅 생성

먼저 호스팅 영역을 생성한다.


생성시 도메인 이름은 가비아에서 구매한 도메인 이름으로 설정했다.

호스트가 생성되었고, 2개의 레코드가 생겨났다.
유형이 NS인 레코드의 트래픽 라우팅 대상 4개의 값이 필요하다. (ns로 시작하는 값들)

구매한 가비아 도메인에 라우팅 대상 설정

이제 가비아 네임서버 설정 페이지에서 트래픽 라우팅 대상 4개의 값을 입력한다.(맨 뒤에 .은 빼준다.)

서브 도메인 생성

DNS 정보 설정을 마쳤다면, 이제 사용자들이 접근할 서브 도메인을 생성할 차례이다.
서브도메인의 경우 보유한 퍼블릭 IP가 있다면 직접 연결하면 되지만,
앞선 포스팅에서 자동 배포를 구현한 next app을 로드밸런서를 통해 서비스 중이므로 해당 로드밸런서를 통해 생성한다.

레코드 생성을 눌러준다.

서브 도메인 레코드를 설정하고, 별칭 토글을 활성화 시키면 트래픽 라우팅 대상으로 로드밸런서를 설정할 수 있다.

필자는 Application Loadbalancer를 통해 next app의 트래픽을 관리하고 있으므로
[Application/Classic Load Balancer에 대한 별칭]을 설정하고, 리전과 로드밸런서를 선택해주었다.


이제 준비가 끝났다.
도메인 활성화 확인하기
위 사이트에 들어가면 방금 등록한 도메인이 정상적으로 열리는지 확인할 수 있다.
(등록하자마자 활성화 되지는 않는다. 시간이 좀 걸린다…!)


결과

Next 프로젝트에 도메인이 생겼다.
이제 누구든 도메인을 통해 내가 만든 프로젝트에 접근이 가능하다.

ECS 서비스 자동 배포 구현하기 (feat. Git Action)

앞선 포스팅에서 ECS Service 까지 생성을 완료하고 확인까지 마쳤다.
이번에는 Git을 통해 ECS Service 자동 배포를 구현하고자 한다.

Task.json 파일 생성

먼저 서비스 생성에 성공한 Task의 Json을 긁어온다.

태스크 정의 - 태스크를 선택하고 JSON - 클립보드 복사 진행

 

그 다음 프로젝트 루트에 [.ecr] -> [prod] -> [task.json] 파일을 생성한다.

{
  "taskDefinitionArn": "arn:aws:ecs:ap-northeast-2:448648424519:task-definition/sample-next-app:latest",
  "containerDefinitions": [
    {
      "name": "sample",
      "cpu": 0,
      "portMappings": [
        {
          "name": "sample-7000-tcp",
          "containerPort": 7000,
          "hostPort": 7000,
          "protocol": "tcp",
          "appProtocol": "http"
        }
      ],
      "essential": true,
      "environment": [],
      "mountPoints": [],
      "volumesFrom": []
    }
  ],
  "family": "sample-next-app",
  "executionRoleArn": "arn:aws:iam::448648424519:role/ecsTaskExecutionRole",
  "networkMode": "awsvpc",
  "revision": 5,
  "volumes": [],
  "status": "ACTIVE",
  "requiresAttributes": [
    {
      "name": "com.amazonaws.ecs.capability.ecr-auth"
    },
    {
      "name": "ecs.capability.execution-role-ecr-pull"
    },
    {
      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
    },
    {
      "name": "ecs.capability.task-eni"
    }
  ],
  "placementConstraints": [],
  "compatibilities": ["EC2", "FARGATE"],
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  },
  "registeredAt": "2023-10-27T01:49:45.973Z",
  "registeredBy": "arn:aws:iam::448648424519:root",
  "tags": []
}

AWS에 있던 Task json에서 containerDefinitions -> image 부분은 삭제한다.
ECR에 Docker Image가 계속 갱신되어서 이미지 버전이 계속 변경되기 때문에 task.json에 고정으로 사용하는건 의미가 없다.

workflow.yml 파일 수정

ECS 자동 배포를 위한 workflow를 추가해준다.

name: Staging # 워크플로 Action의 이름
on:
  push:
    branches: [main] #github main 브런치에 푸시 발생 시 실행 ( main 외 다른브런치 이용시 이름변경)
jobs:
  staging: #staging이라는 작업
    name: deploy to staging # 작업의 이름
    runs-on: ubuntu-latest # 실행될 작업환경을 말함.
    steps:
      - name: Checkout
        uses: actions/checkout@v3 #체크아웃 받기
      - name: HelloWorld
        uses: actions/hello-world-javascript-action@v1 # 헬로월드 찍어보기
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # Github Secret 이름
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # Github Secret 이름
          aws-region: ap-northeast-2 # AWS 리전 선택
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: sample # ecr 이름
          IMAGE_TAG: ${{ github.run_number }} # git 커밋넘버를 이미지 이름 구분을 위해 넣어줌
        run: |
          # Build a docker container and
          # push it to ECR so that it can
          # be deployed to ECS.
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: .ecs/prod/task.json # task파일
          container-name: sample #이미지 컨테이너 이름
          image: ${{ steps.build-image.outputs.image }}
      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: sample-ecs-service #클러스터 서비스 명
          cluster: sample-cluster # 클러스터 명
          wait-for-service-stability: true

ECS task definition 부분부터 추가해주면 된다.

page.tsx 내용 수정

이제 next app의 내용을 수정해서 자동 배포 후 정상적으로 적용되는지 확인해본다.

export default function Home() {
  return (
    <div>
      <h1>Hello Next.js!</h1>
      <h2>feat. CI/CD with AWS-ECS</h2>
    </div>
  );
}

결과

이로써 ECS 자동배포까지 구현이 완료되었다.

다음 포스팅에서는 Route53으로 그럴싸한 도메인을 붙이는 과정을 진행해보고자 한다.

–끝–

ECS Cluster 생성

Cluster란?
ECS 클러스터는 Docker Container를 실행할 수 있는 논리적인 공간이다.
ECR에 등록한 Docker Image를 가지고 컨테이너를 구성하려면 이 클러스터를 생성 및 사용해야 한다.

클러스터 이름을 sample-cluster로 짓고, 나머지 설정은 그대로 둔 후 생성한다.

인프라 탭에서 주로 Fargate와 EC2 인스턴스 둘을 사용한다.
간략하게 두 인프라의 차이점을 살펴보면 아래와 같다.


EC2인스턴스
EC2는 AWS에 대표적인 서비스 중 하나이다. 주로 서버로 사용하며, 비용을 지불하고 가상의 서버를 대여 받을 수 있다.

ECS 서비스를 구축할 때 EC2 인스턴스를 인프라로 선택하면 서비스에 속한 EC2 인스턴스 서버와 클러스터를 직접 관리해주어야 한다.

Fargate
EC2 인스턴스와 다르게 서버 인스턴스를 관리할 필요가 없는 컨테이너 서비스이며 사용량에 따라 요금이 부과되는 종량제 형식으로 제공된다.
(서버리스란 서버가 없다는 것이 아니다. 서버가 필요한 순간이 왔을 때 잠시 서버를 깨워 기능을 수행하고 다시 잠든다. 이렇게 종량제 서비스가 되는 것이다.)

EC2 인스턴스와 Fargate는 상황에 맞게 잘 고려해서 선택하면 될 것 같다.


Task 정의 생성

다시 본론으로 돌아와서 클러스터를 생성했다면, 이제 Task 정의를 생성한다.

클러스터를 생성할 때 인프라를 Fargate로 생성했으니 시작 유형을 AWS Fargate로 설정한다.
태스크 크기는 CPU : 0.25vCPU, 메모리 : 0.5GB 으로 설정한다. (캡처와 다르니 참고)

컨테이너 이름은 sample로 지었다.
이미지 URI는 지난번 ECR에 등록된 이미지 URI를 복사해서 사용한다.
여기서 주의할 점이 있는데, 레포지토리 URI가 아닌 이미지 URI를 복사해야한다.
(그래야 sample:${version}까지 복사된다.)


다음, 포트 매핑에서는 컨테이너 포트를 7000으로 설정한다.
Docker File에서 Port를 7000으로 설정했기 때문에 여기서도 맞춰준다.

이후에는 기본 값으로 두고 작업을 생성한다.


서비스 생성

앞서 클러스터와 Task를 정의 한 것은 바로 서비스를 생성하기 위함이다.
이제 대망의 서비스를 올려보자!

생성한 ECS 클러스터를 클릭하면 서비스 생성이 가능하다.


컴퓨팅 옵션 : 시작 유형
시작 유형 : Fargate
플랫폼 버전 : LATEST



태스크 : 2 (Fargate 인스턴스가 2개 생성된다.)



네트워킹은 별도로 건들지 않았다.
로드밸런서 및 대상 그룹은 서비스를 생성하며 함께 생성해준다.


서비스가 정상적으로 생성되고 활성화가 되었다.

이제서야 비로소 개인 프로젝트가 모든 서버 인스턴스에 Docker를 통한 동일한 서비스 환경을 구축한 것이다.

아래 로드밸런서 DNS 이름의 주소를 가지고 웹에서 나의 프로젝트를 확인할 수 있다.

결과 화면


마무리하며

포스팅을 하면서 서버와 네트워크에 대해 점점 친숙해지는 기분이다.
사실 여기까지의 과정에서 우여곡절이 많았지만 시간이 걸려도 해내면 그만이다.

다음 포스팅에서는 Git을 통한 ECS 서비스 자동 생성을 구현해볼 예정이다.

글을 읽으시는 모든 분들께 알량한 나의 지식이 도움이 되었으면 한다.

AWS - ECR 레포지토리 생성

ECR 레포지토리를 생성해준다.

우선은 연습용으로 사용할 것이기 때문에 프라이빗으로 생성하고, 레포지토리 이름은 "sample"로 지정했다.

docker file 작성

(docker를 미리 설치해주세요 ^^)
이제 ECR 레포지토리를 생성했으니, 해당 레포에 도커 이미지를 등록하기 위해 dockerfile을 만들어준다.
(도커파일 만드는 방법)
(본인의 프로젝트에 맞게 작성하면 된다.)
이번 Next sample 프로젝트를 docker image로 만들기 위해 아래와 같이 작성한다.

FROM node:18-alpine

WORKDIR /app

COPY package.json ./

RUN npm install

#프로젝트의 모든 파일을 복사
COPY . .

RUN npm run build

#포트 7000번 사용
EXPOSE 7000

CMD ["npm", "run", "start"]

github workflow 수정

작성한 docker file을 기반으로 AWS-ECR에 docker image를 자동으로 push할 수 있도록 workflow.yml을 수정한다.

name: Staging # 워크플로 Action의 이름
on:
  push:
    branches: [main] #github main 브런치에 푸시 발생 시 실행 ( main 외 다른브런치 이용시 이름변경)
jobs:
  staging: #staging이라는 작업
    name: deploy to staging # 작업의 이름
    runs-on: ubuntu-latest # 실행될 작업환경을 말함.
    steps:
      - name: Checkout
        uses: actions/checkout@v3 #체크아웃 받기
      - name: HelloWorld
        uses: actions/hello-world-javascript-action@v1 # 헬로월드 찍어보기
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # Github Secret 이름
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # Github Secret 이름
          aws-region: ap-northeast-2 # AWS 리전 선택
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: sample # ecr 이름
          IMAGE_TAG: ${{ github.run_number }} # git 커밋넘버를 이미지 이름 구분을 위해 넣어줌
        run: |
          # Build a docker container and
          # push it to ECR so that it can
          # be deployed to ECS.
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

name : Build, tag, and push image to Amazon ECR << 이 부분부터 추가했다.

Git Action / ECR Repository 확인

이제 작성한 docker file과 github workflow를 커밋 & 푸시하여 git action을 통한 docker image 자동 배포를 확인해볼 차례이다.

필자는 workflow의 run 부분을 잘못하여 좀 돌아왔지만 결국 성공했다.

AWS - ECR에도 정상적으로 Image가 push되었다.


마무리하며

이번 포스팅으로 ECR에 docker image를 자동 배포하는 과정을 알아보았다.
여기까지만 해도 기본적인 docker 및 AWS에 대한 지식이 필요하기 때문에 순탄치만은 않았던 것 같다.

다음 포스팅에서는 대망의 ECS 연동 및 자동배포를 다룰 예정이다. (제일 어려운 부분이 될 것 같다.)

화이팅…!!

+ Recent posts