0%

Update the source code

코드를 업데이트하고 적용하는 방법을 알아본다.

  1. 코드를 고친다.
  2. build 할때 사용했던 명령어를 똑같이 입력한다.
1
$ docker build -t getting-started .
  1. 업데이트된 코드를 사용해서 새로운 컨테이너를 시작한다.
1
$ docker run -db 3000:3000 getting-started

하지만 에러가 발생한다.. (docker: Error response from daemon: driver failed….)

왜냐하면 이미 3000 번 포트로 전에 컨테이너가 실행중이기 때문이다. 하나의 머신에 특정한 포트는 한게만 실행 실행시킬 수 있다. 오래된 컨테이너를 지워야 한다.

Replace the old container

컨테이너를 지우기 위해서는 컨테이너 실행을 중지 시켜야 한다. 두가지 방법이 있는데 편한것을 선택하면 된다.

Remove a container using the CLI

  1. 컨테이너의 ID를 얻는다.
1
$ docker ps
  1. docker ID 혹은 이름을 사용해서 컨테이너를 멈춘다.
1
$ docker stop <the-container-id or name>
  1. 컨테이너가 멈추면 docker rm 커멘드로 지울 수 있다.
1
$ docker rm <the-container-id or name>

-f 플래그를 이요해서 실행중인 중에도 삭제할 수 있다. docker rm -f <the-continaer-id or name>

Docker Dashboard

Docker Dashboard에서 실행중인 컨테이널르 확인하고 쓰레기통 아이콘을 누르면 삭제할 수 있다.

Start the updated app container

  1. 앱을 실행시킨다.
1
$ docker run -dp 3000:3000 getting-started

develop app

Intro

이전 섹션에서 구축한 애플리케이션을 위한 로컬 개발 환경을 설정하는 과정을 살펴본다.

Local database and containers

이번 섹션에서는 MongoDB를 사용한다. MongoDB를 직접 다운로드 하는것 대신에 Docker 공식 이미지를 사용하도록 한다.

MongoDB Container 를 실행하기 전에 Data를 저장할 수 있는 볼륨을 설정한다. Docker 가 제공하는 volumes 기능을 사용한다.

data와 MongoDB 설정 볼륨을 만든다.

1
2
$ docker volume create mongodb
$ docker volume create mongodb_config

애플케이션과 database가 소통할 네트워크를 생성한다. 네트워크는 사용자 정의 브리지 네트워크라고 하며 컨테이너간 소통할때 사용할 수 있는 DNS 조회 서비스를 제공한다. (mongodb 로 접속할 수 있게 DNS 제공)

1
$ docker network create mongodb

이제 컨테이너에서 mongoDB를 실행하고 볼륨과 네트워크를 연결한다.

1
2
3
4
5
$ docker run -it --rm -d -v mongodb:/data/db \
-v mongodb_config:/data/configdb -p 21017:21017 \
--network mongodb \
--name mongodb \
mongo

server.js 를 수정해서 mongoDB를 사용하도록 한다. process.env.CONNECTIONSTRING 과 같이 환경 변수를 조회하고 있는데 나중에 컨테이너를 실행시킬때 CONNECTIONSTRING 이라는 이름에 환경변수를 추가할 수 있다.

1
2
3
4
5
6
7
8
const ronin     = require( 'ronin-server' )
const mocks = require( 'ronin-mocks' )
const database = require( 'ronin-database' )
const server = ronin.server()

database.connect( process.env.CONNECTIONSTRING )
server.use( '/', mocks.server( server.Router(), false, false ) )
server.start()

ronin-database 를 추가했으므로 설치한다.

1
$ npm i ronin-database

build 한다.

1
$ docker build --tag node-docker .

컨테이너를 실행시킨다. 여기서 CONNECTIONSTRING 환경변수를 추가해서 애플리케이션이 어떻게 데이터베이스에 접근해야 하는지 알려준다.

1
2
3
4
5
6
7
$ docker run \
-it --rm -d \
--network mongodb \
--name rest-server \
-p 8000:8000 \
-e CONNECTIONSTRING=mongodb://mongodb:27017/yoda_notes \
node-docker

Use Compose to develop locally

하나의 명령으로 node-docker 와 MongoDB를 시작하는 Compose 파일을 생성해 본다. 또한 컴포즈 파일로 node-docker 를 시작할때 debug mode로 시작하게 해서 실행중인 프로세스에 디버거를 연결할 수 도 있다.

docker-compose.dev.yml 파일을 만들어서 다음 내용을 복사한다.

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
version: '3.8'

services:
notes:
build:
context: .
ports:
- 8000:8000
- 9229:9229
environment:
- SERVER_PORT=8000
- CONNECTIONSTRING=mongodb://mongo:27017/notes
volumes:
- ./:/app
command: npm run debug

mongo:
image: mongo:4.2.8
ports:
- 27017:27017
volumes:
- mongodb:/data/db
- mongodb_config:/data/configdb
volumes:
mongodb:
mongodb_config:

compose 파일을 이용하면 docker run 할때 사용했던 여러가지 파라미터를 컴포즈 파일에 명시함으로써 생략할 수 있다.

  • 디버거를 연결할 수 있는 9229 포트를 노출한다.
  • services 에서 설정한 이름을 서비스에서 설정할 수 있다. 이경우에는 mongo 가 된다.
  • 디버거 모드로 실행하기 위해서 package.json 에 스크립트를 추가한다.
1
"debug" : "nodemon --inspect=0.0.0.0:9229 server.js"

nodemon을 사용함으로 nodemon을 설치한다

1
$ npm i nodemon 

애플리케이션을 시작한다.

1
$ docker-compose -f docker-compose.dev.yml up --build

docker 이미지를 컴파일한 다음 시작하도록 —build 플래그를 전달한다.

디버깅 모드로도 실행되고 8000 번 포트로 접근할 수 도 있다.

1
$ curl --request GET --url http://localhost:8000/notes

Connect a debugger

크롬 브라우저와 함께 제공되는 디버거를 사용할 수 있다. 크롬을 열고 주소창에 about:inspect 를 입력한다.

depends_on

어떤 컨테이너는 다른 컨테이너의 의존해서 실행 순서가 나중이어야 하는 경우가 있다. mysql을 사용하면서 특정 테이블이 생성되기 전에 server에서 접근하면 에러가 발생하는데 이런경우 mysql 컨테이너가 테이블을 만드는 시점보다 server 가 실행되는 시점이 더 빠르기 때문이다. 의존성을 추가하고 싶다면 depends_on 을 사용하여 의존성을 명시해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
services:
notes:
depends_on:
- mysqldb
build:
context: .
ports:
- 443:8080
- 9229:9229
environment:
- SERVER_PORT=8080
- DB_PORT=3306
- MYSQL_DATABASE=test
- USER=root
- MYSQL_ROOT_PASSWORD=1q2w3e
- HOST=mysqldb
volumes:
- ./:/app
command: yarn run debug

Run Containers

Overview

컨테이너는 host 와는 격리된 자기 자신만의 파일시스템, 네트워크 프로세스를 가지고 있다. 저번 시간에 이어서 이미지를 실행 보도록 한다,

1
$ docker run node-docker

하지만 이렇게 하면 요청이 거부 된다는 결과만 나온다. 이유는 docker 컨테이너는 host 와 격리되어 있기 때문이다. 따라서 포트를 매핑 시켜야 제대로 실행시킬 수 있다.

1
$ docker run --publish 8080:8080 node-docker

-p 로 축약해서 사용 가능하다.

Run in detached mode

detached모드로 백그라운드에서 실행시킬수도 있다.

1
$ ocker run -d -p 8080:8080 node-docker

-d 와 -p 옵션을 합쳐서 -dp로 사용 가능하다.

List containers

현제 실행되고 컨테이너 갯수와 어떤 컨네이너가 실행되어 있는지는 docker ps 로 확인할 수 있다.

docker stop 으로 컨테이너 id 나 이름을 주어서 컨테이너를 종료시킬 수 있다.

Stop, start, and name containers

docker ps 에 기본값은 실행중인 컨테이너를 보여주는 것이다. docker ps -a 플래그를 넣어주면 모든 컨테이너 상태를 볼 수 있다.

  • docker restart 에 아이디나 종료된 컨테이너의 이름을 넣어주면 도커 컨테이너를 재실행 시킬 수 있다. restart 를 실행하면 처음 실행할 때 사용했던 플래그나 커맨드를 똑같이 사용한다.

이제 컨테이너의 이름이 랜덤으로 바뀌는 이슈를 고쳐 보자. 컨테이너 이미지를 기본적으로 실행하면 랜덤한 이름이 정해진다.

기존에 실행해서 랜덤하게 생성되었던 컨테이너를 지운다.

  • docker rm <컨테이너 이름>

여러 이름을 한꺼번에 넣을 수 도 있다.

이제 컨테이너의 이름을 랜덤이 아닌 정해진 것으로 설정해 보자. 개발할때 변수에 이름을 짖는것처럼 식별하기 쉽고 읽기 쉽게 정하는 것이 좋다. 이름을 설정하기 위해서는 단순히 —name 플래그를 더해주기만 하면 된다.

1
$ docker run -dp 8080:8080 --name naver-api node-docker

Sample application

Build the app’s Container image

Dockerfile은 컨테이미지를 만드는 구조의 스크립트이다. Dockerfile을 통해서 이미지를 만들어 본다.

  1. create file named Dockerfile in the same folder as the file package.json with the follwing contents.
1
2
3
4
5
6
7
# syntax=docker/dockerfile:1
FROM node:12-alpine
RUN apk add --no-cache python3 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
  1. Dockerfile이 있는 폴더로 이동한 후에 build 를 시작
1
$ docker build -t getting-started .

이 커멘드는 Dockerfile 을 사용해서 컨테이너 이미지를 만든다.

Start an app container

  1. docker run 을 통해 이미지를 실행시킨다.
1
$ docker run -dp 3000:3000 getting-started

다시한번 설명하자면 :

  • -d : background 실행
  • -p : 포트 매핑 host 3000 번 을 docker image 의 3000번 포트로
  1. localhost:3000 으로 접속하면 내용을 확인할 수 있다.

Docker Dashboard 에서 continaer 탭을 살펴보면 여러가지 컨테이너가 실행중인 것을 불수 있다. 다음에는 컨테이너를 관리 하는 방법을 살펴본다.

Getting Started

배우는 것

  • 이미지를 컨테이너로 빌드 및 실행
  • Docker hub를 통해서 이미지 공유
  • 여러개의 컨테이너를 포함하는 Docker applications 배포
  • Docker Compose 를 통한 applications 실행

Start

docker run -d -p 80:80 docker/getting-started

  • docker/getting-started 를 실행시킴. 로컬에 없으면 registry에서 pull 한다음 실행하는 것과 동일
  • -d : backgroudn 로 실행시킴
  • -p 80:80 : host 에 80 포트를 컨테이너의 80포트로 매핑함.

⇒ db로 flag를 줄일수 있음.

What is a container?

간단히 말하면, 호스트 머신과 분리된 sandboxed process 이다.

  • 실행 가능한 이미지의 인스턴스이다. create, start, stop, move or delete를 Docker API나 CLI를 사용해서 할 수 있다.
  • 로컬이나 클라우드 가상 머신 어디든지 실행 가능하다.
  • 어떤 os 든지 실행 가능하다.
  • 컨테이너는 서로 격리되어 있으며 자체 소프트웨어, 바이너리 및 구성을 실행한다.

What is a container image?

컨테이널르 실행할때 격리된 파일 시스템을 사용하고 이미미지는 컨테이너의 파일 시스템을 포함한다. 또한 컨테이너를 실행시키는데 필요한 어떤 설정이다. 의존성, 바이너리, 스크립트 등도 포함한다.

Build your Node image

Enable BuildKit

BuildKit을 활성화 해서 이미지를 효과적으로 빌드 할것을 추천한다. Docker Desktop을 사용한다면 자동으로 설정 되어 있다.

Overview

이미지에는 애플리케이션을 실행하는 데 필요한 모든것(코드, 바이너리, 런타임, 종속성 및 기타 필요한 파일 시스템 개체)이 포함된다.

Create a Dockerfile for Node.js

Dockerfile 은 Docker image를 모으는 지침을 포함하는 텍스트 파일이다. docker build 와 같은 명령어를 사용하면 Dockerfile에서 읽어서 실행한다.

  • 프로젝트 root 경로에 Dockerfile을 만든다.
  • #syntax 를 적용한다. build 하기 전에 항상 최신 버전을 사용하는 등의 작업을 수행하게 할 수 있다. docker/dockerfile:1 은 항상 최신버전을 가르킨다.
1
# syntax=docker/dockerfile:1
  • base image 파일을 설정한다.
1
FROM node:12.18.1

상속 가능하다. 즉, 직접 만든 것도 사용 가능 하지만 다른 이미지를 사용할 수 도 있다. 따라서 어플리케이션에 필요한 기능이 모두 담긴 이미지를 base image로 설정할 수 도 있다. 상속과 마찬가지로 FROM 을 사용하면 해당 이미지에 모든 기능을 사용하는 다른 이미지를 만들 수 있다.

  • 환경을 설정한다. 주로 production 이다 development 가 될 수 있다.
1
ENV NODE_ENV=production
  • 다른 명령을 쉽게 실행 시키기 위해서 working dir을 설정한다. 기본 패스로 사용해서 다른 명령어를 입력할때 모든 패스를 사용하지 않아도 된다.
1
WORKDIR /app
  • node 프로젝트에서는 의존성을 설치하기 위해 package.json을 사용하는데 이미지 파일에도 package.json을 옮겨야 한다. COPY 명령을 사용하고 인자로 srcdest 를 받는다. src 는 복사하고 싶은 파일을 의미하고, dest는 복사하고 싶은 곳을 의미한다.
1
COPY ["package.json", "package-lock.json*", "./"]
  • 의존성을 설치하는 명령을 실행한다.
1
RUN npm install --production
  • 이제 모든 파일을 복사한다. 이미지 파일로 복사한다.
1
COPY . .
  • 컨텐스트 로드 시간을 줄이기 위해서 .dockerignore 파일을 생성한다.
1
node_modules

build image

docker build 명령을 실행시켜서 build 할 수 있다. --tag 옵션을 주면 이미지에 이름을 줄 수 있다.

1
$ docker build --tag node-docker .

이미지는 manifest와 layer로 구성된다

Dockerfile

1
2
3
4
5
6
7
8
9
10
# syntax=docker/dockerfile:1
FROM node:14.16.0

COPY ["package.json", "yarn.lock", "./"]

RUN yarn install

COPY . .

CMD ["yarn", "start"]

NODE_ENV 는 따로 설정 안해서 뺐음

211215

백엔드

  • 유효성 검사 어디에서 하는게 좋을까?
    • 서버에서 검증을 빨리 하는것이 좋은데 네트워크를 소비하지 않도록 클라이언트에서 검증을 해도 좋다. 하지만 서버에서 검증하는 절차는 필수적이다.
  • 유효성 검사를 위해서 expres-validator 를 이용할 수 있다.
  • Sanitization 이란 ? 유효성 검사 후에 해야 하는데 예를 들어 2 글자 이상의 벨리데이션이 있었다면, 공백만 3글자로 입력해도 통과 됨. 이런것도 다 잡아줘야 함 → 이경우에는 맨 처음 trim()을 사용해서 해결 가능. express-validator 다양한 Sanitization 을 관련 API를 제공한다. ⇒ 데이터를 일관성있게 적용될 수 있도록
  • validation 관련한 함수는 middleware로 따로 관리한다 controller는 비즈니스 관련 핵심 로직만 관리 할 수 있도록 한다.
  • Contract Testing: Client-Server 통신시 test, 나중에 공부해보자.

프론트

  • react-query: server 에 상태를 캐쉬해서 network 비용을 줄일 수 있게 해준다. redux 를 사용하면 client 에 상태는 잘 관리할 수 있지만 server의 상태를 관리하려면 캐쉬등 여러가지 해주어야 할 작업이 있다. 이 책임을 reqct-query 에게 줌으로써 개발자는 다른 것에 집중해서 개발할수 있다.
  • 데이터를 처음 가져올때는 state를 통해 loading, success, error 와 같은 상태를 사용할 수 있고, 두번째로 가져올 때부터는 server 상태와 동기화 되서 다를때만 가져오고 나마저는 캐쉬된 상태를 사용할수 있게 함으로써 사용자 경험을 높인다.
  • 전역 state는 어떻게? → ContextAPI를 사용하여 전역 상태를 관리 할 수도 있다. 요즘은 redux 에 비중을 줄이고 context 와 react-query에 조합을 많이 사용하기도 한다.

리액트 네이티브

  • react-native-safe-area-context : safe area 나머지 부분에 여백에 관한 설정을 할수 있는 라이브러리
  • 안드로이드에 경우 자동으로 서드파티 라이브러를 불러와서 사용할 수 있지만 ios에 경우에는 cocoapods 의 도움을 받아야 네이티브 모듈의 적용할 수 있다. ios 폴더 이동후 pod install 을 실행한다.
  • react-native-safe-area-context 의 useSafeAreaInsets() hook을 이용하면 반환 값으로 각 safeArea 구성의 필요한 각 모서리에 공백을 top, bottom, left, right로 받아올 수 있다.
  • statusBar 의 barStyle props를 전달할 수 있다. dark-content(어두운 내용), light_content(밝은 내용), default(시스템 기본 설정) → 참고로 안드로이드 ios 공통으로 사용할 수 있다.
  • 리액트 네이티브에서 스타일링할 때 크기는 모두 dp로 설정한다. (Density-independent Pixel) → 1인치당 픽셀 밀도에 따라 크기가 일관된 UI를 보여줄 수 있는 단위이다.
    • dp = px * 160 / ppi
    • px = dp * ppi / 160
  • 시뮬레이터 디바이스를 변경하는 방법 → xcrun simctl list devices 를 통해 실행 가능한 디바이스 목록을 확인할 수 있고, yarn react-native run-ios- simulator="iPhone 5s 와 같은 방법으로 동작 시킬 수 있다. 안드로이드의 경우에는 Android Virtula Device Manager를 열어서 Create Virtual Device 버튼을 눌러 새 디바이스를 추가하면 된다.
  • 이미지를 리사이즈 해서 실제 이미지와 크기가 달라질때, resizeMode를 설정할 수 있다.
    • cover: 기본값, 가로 세로 비율을 유지한채로 리사이징, 뷰가 더 작으면 이미지가 잘린다.
    • contain: 가로 세로 비율을 유지한 체로 리사이징 하며 무조건 영역에 모두 들어오도록 한다.
    • stretch: 뷰의 크기대로 이미지를 리사이징 한다. 비율이 달라진다.
    • repeat: 바둑판식으로 이미지를 반복한다.
    • center: 이미지를 뷰 중앙에 둔다. contain과 마찬가지 이고, 뷰가 이미지보다 크면 이미지의 크기가 커지지 않고 원본 사이즈를 유지한다.

Docker Overview

What can I use Docker for?

  • CI/CD WorkFlows
  1. 개발한 코드를 도커 컨테이너와 함께 공유한다.
  2. Docker 를 사용하여 애플리케이션을 테스트 환경으로 푸시하고 자동화 및 수동 테스트를 실행함.
  3. 버그를 발견하면 개발 환경에서 고치고 다시 테스팅과 검증을 위해 제배포 할 수 있다.
  4. 테스트 까지 완료되면, 고객에게 전달하는것은 단지 production 환경으로 이미지를 push 해서 업데이트 하면 끝인 간단한 작업이다.

Docker architecture

  • Docker daemon (dockerd):

Docker API 요청을 수신하고 이미지, 컨테이너, 네트워크 및 볼륨과 같은 Docker 객체를 관리한다. 다른 daemon 과 통신할 수 도 있다.

  • The Docker client (docker):

docker run 과 같은 명령어를 실행하면 Docker client는 dockerd 로 명령을 옮긴다. Docker client는 둘이상의 docker daemon과 통신할 수 있다.

  • Docker Desktop :

Window와 Mac 에서 도커 애플리케이션을 공유할수 있게 해준다. dockerd , docker , Docker Compose, Docker Content Trust.. 같은것을 포함한다.

  • Docker registries :

Docker hub 와 같이 이미지들을 모아 둔 곳,

Docker Object

docker images, containers, networks, volumes, plugins.. 등등 다양한 오브젝트가 있다. 간단하게 몇게만 살펴본다.

  • images :

컨테이너를 생성 지침이 포함된 읽기 전용 템플릿이다. 이미지를 이용해서 커스텀한 이미지를 만들 수도 있다. Dockerfile 을 만들어서 image를 생성하고 실행하는 스텝을 정의할 수도 있다. Dockerfile의 각 지침은 image layer를 만든다.

  • Containers :

컨테이너는 이미지에 실행가능한 인스턴스이다. 기본적으로 각 컨테이너와 host는 잘 격리 되어 있고, 얼마나 격리 될지 정할 수 도 있다. 만들때 설정한 설정과 이미지들로 컨테이너가 정의 된다.

Docker

가상 os를 사용해본 경험이 한번쯤은 있을 것이다. 가상 os는 vm 같은 프로그램을 사용해서 현제 os 위에 새로운 os를 설치하는 것인데 이를 통해서 다른 host os 와는 다른 os를 사용할 수 있게 된다.

vm ware와 같은 소프트웨어에서는 hostos 위에 hypervisor 를 두어서 그 위에 가상 os를 설치하는 방법을 사용한다. 이때 하드웨어 리소스를 필요한 부분 만큼 떼어 놓고 그 리소스 안에서 os를 사용하게 되는데 성능상에 손실이 있을 수 있다.

그에 반에 Docker는 Docker engine 을 사용하여 프로세스 수준으로 리소스를 격리할 수 있다.

Docker를 사용하는 이유?

  1. 컨테이너 이미지의 용량이 적다.
  2. 배포 속도가 빠르다.
  3. 가상화된 공간을 사용할 때의 성능손실이 적다.

Docker 설치

설치 docs 우분투에 대한 내용은 여기서 찾아 볼 수 있다. 문서를 보고 다른 os도 따라서 해보면 된다.

211213

백엔드

  • 배포 채크리스트
    • 보안 관련한 키가 포함되어 있지 않은지?
    • 보안의 위헙이 되는 로그를 남기지 않는지?
    • 반응으로 민감한 정보를 넘기고 있지 않은지
    • API reate limits 를 정해야 한다. 사용자가 계속 API 요청을 반복적으로 하지 못하도록 막는것
  • mysql Aws 에서 사용하는 방법
    • 서비스 → RDS (관계형 데이터 베이스 생성)→ 대시보드 → 데이터 베이스 생성 → 표준생성 , 손쉬운 생성은 알아서 늘어남.. 과금 될 수도
    • mysql 설정
    • 텝플릿 ? 무료로 쓰려면 프리티어로
    • DB 인스턴스 → DB 이름 정하기
    • 자격 증명 설정 (꼭 기억) - 이름 비밀저호 설정
    • 스토리지 기본 20g , 스토리지 자동 조정 활성화 켜져 있으면 늘어나고 그럼 과금이 시작됨. 무료로 사용하려면 비활성화 해줌.
    • 퍼블릭 엑세스 예로 체크 dbeaver 같은데서 접근 가능하도록
    • 외부 접속 방법?
      • 서비스 → EC2 → 인스턴스 → 네트워크 및 보안 → 보안 그룹 → 인바운드 규칙 (외부로부터 열어놓을 포트)
      • 인바운드 규칙 편집 → 규칙 추가 → MySQL/Aurora 선택 → 기본포트로 3306 설정됨 aws msql default 값→ IP 대역 설정 0.0.0.0/0 어떠한 주소에서도 가능. → 규칙 저장
      • 다시 RDS 이동 → 열결및 보안 → 엔드포인트 및 포트 에서 엔드 포인트 확인 → 확인한 정보로 접속

GraphQL

  • 기존 RestAPI 의 단점을 보완해서 쿼리를 보내서 원하는 정보만 가져오도록 함.
  • 다양한 방법이 있는데 Apollo로 Server을 만들어서 구현해 볼 수 있다. (apollo-server)
  • typeDef : grapQL 스키마, Object(데이터 스키마), Query (쿼리 형태, 조회 할때), Mutaion( 생성, 변경, 삭제 할때 , resolve 도 mutation으로 설정해야 함.), Input → gql + tagged template Literals
  • resolvers : 구현체