반응형

제목은 NODE_ENV 값을 설정하는 방법 처럼 보이지만, 사실은 좀 다른 부분이 있습니다.

 

React에서는 환경변수를 사용할때, 항상 REACT_APP_XXXX 형태로 사용해야 인식이 됩니다.

그런데 NODE_ENV는 어디서 튀어 나온걸까요?

 

.env 파일에 여러 REACT_APP_XXX 하는 환경 변수들과 더불어, NODE_ENV=production 으로 작성해놓은 파일을 보기도 할것인데요.

react에서는 이 .env에 적혀있는 값이 불려지는 것이 아닙니다.

 

**Create React App (CRA)**에서는  다음처럼 NODE_ENV를 자동 설정합니다.

명령어 NODE_ENV 값
npm start development
npm run build production
npm test test

 

즉 npm run build 했을때, production optimization 되고 NODE_ENV 값이 production으로 값이 적용되게 되는 것이죠.

 

보통 npm start로 로컬에서 테스트 하는데 이럴때는 항상 NODE_ENV는 development가 됩니다.

 

그렇다면  production 처럼 테스트 할 수 있는 방법이 없을까요?

npm install -g serve
npm run build
serve -s build

 

이렇게 serve -s build 를 이용하여 build 된 결과물을 실행시켜서 테스트 해볼 수 있습니다.

 

환경변수 파일 관리

NODE_ENV 에 따라 환경변수 파일을 다르게 적용 할 수도 있습니다.

.env.production => production일때 적용

.env.development => development 일때 적용

 

 

 

 

#해피코딩 !!

반응형

 

 

종종 한글 조사 때문에 골치 아플 때가 있죠?

 

"${who1}(은/는) ${who2}(을/를) 사랑합니다."

 

과거에 이렇게 사용한 적이 있었는데, 사실 좀 보기 안좋죠?? 

 

조사 처리를 위한 함수를 하나 만들었습니다. (다른 곳에서 참조하여)

 

유니코드 초성/중성/종성 확인 방법


초성 인덱스 = ((한글 유니코드값 - 0xAC00) / 28) / 21
중성 인덱스 = ((한글 유니코드값 - 0xAC00) / 28) % 21
종성 인덱스 = (한글 유니코드값 - 0xAC00) % 28

 

const getJosa = (name: string,josa1:string,josa2:string) => {
  const lastChar = name.charCodeAt(name.length - 1)
  const isThereLastChar = (lastChar - 0xac00) % 28
  if (isThereLastChar) {
    return josa1
  }
  return josa2
}

 

 

이 함수를 이렇게 사용할 수 있습니다.

const getTextChanges = (field: string, oldValue: any, newValue: any) => {

    return t("changed.desc", {
      field,
      josa: getJosa(field,'이','가'),
      oldValue,
      newValue
    })
  }

 

ko.json

"changed.desc": "{{field}}{{josa}} \"{{oldValue}}\" 에서 \"{{newValue}}\" 으로 변경되었습니다",

 

 

 

[참고] https://velog.io/@hjkdw95/%ED%95%9C%EA%B5%AD%EC%96%B4-%EC%9D%80%EB%8A%94-%EC%9D%B4%EA%B0%80-%EC%99%80%EA%B0%80-javascript%EB%A1%9C-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0

 

한국어 은/는 이/가 와/가 javascript로 처리하기

참 쉽습니다

velog.io

 

# 해피코딩!!

반응형

React의 상태관리를 위한 방법들이 몇가지가 있는데요.

그중에서 zustand를 소개하고자 합니다.

 

상태관리

주요한 상태관리 방식은 다음과 같습니다.

 

방식사용 도구 / 패턴추천 상황

React Context + useReducer 내장 상태 관리 소규모 앱, 글로벌 상태 많지 않을 때
Zustand / Jotai / Recoil 경량 상태관리 중소 규모 앱, 간단하게 쓰고 싶을 때
Redux Toolkit 표준 Redux 중대형 앱, 상태 변화 복잡할 때
BLoC 패턴 (구현형) 커스텀 Hook + 클래스/Stream 구조 Flutter에서 익숙한 개발자, 로직-UI 분리를 철저히 하고 싶을 때
❌ 단순 useState 남발 없음 상태가 많아지면 혼돈 💥

 

상태관리 및 모듈화 (또는 구조화) 하는 것은 소프트웨어 유지보수 및 제사용성을 높이고, 품질 향상을 위해서 진행합니다.

 

DI (Dependancy Injection) 구조는  테스트를 위해서 필요한 요소이기도 합니다.

때문에 DI framework을 고려하기도 하죠.

 -  Factory + DI Framework (ex: Inversify, NestJS 등)

 

 

상태관리 방법 상황별 추천 

소규모 프로젝트 Context + useReducer, Zustand
중/대형 앱, 많은 비즈니스 로직 Redux Toolkit
Flutter BLoC 경험자 커스텀 BLoC 구조 or MobX-State-Tree
단순한 상태만 있다 useState, useContext로 충분

 

 

상태 관리시 고려할 사항이 한가지 더있습니다.

 

전역 상태에 두는 것이 적절한 조건 설명

조건  설명
🔁 여러 컴포넌트에서 공유됨 예: 리스트 → 상세 → 수정
🔒 로그인 유저 전용 데이터 로그인 후 고정된 데이터
📦 비교적 작거나, 페이지 단위 데이터 수십~수백 개 수준

❌ 다만, 데이터 양이 너무 크거나 자주 바뀌면, 메모리/리렌더 성능 문제가 생길 수 있음.

 

 

 

전역 상태로 인한 메모리/성능 이슈

이슈 유형 설명 대응 방법
데이터가 수천~수만 개 예: works가 10,000건 이상 페이징, 무한스크롤, 서버 캐시
모든 상태 변경이 전체 리렌더 유발 Redux/Context에서 너무 많은 컴포넌트가 구독 Zustand 같은 부분 구독 상태관리 추천
works 자체가 큰 객체 파일 포함, 이미지 base64 등 저장 대신 ID만 들고 있고, 세부 정보는 lazy fetch

 

 

✅ 성능 좋게 전역 상태를 유지하는 팁

1. 필요한 데이터만 저장하기

예: 전체 works 배열 대신 worksMap: { [id]: Work } + workIds: string[] 같이 분리 저장

2. 컴포넌트별로 부분 구독

Redux Toolkit + useSelector (메모이제이션)

Zustand는 기본적으로 부분 구독이라 성능 좋음

3. 서버 캐싱 도구 활용

React Query / SWR로 데이터를 “전역처럼” 쓰고 자동 캐싱/패칭 활용

4. LocalStorage / IndexedDB 연계

너무 큰 데이터는 브라우저 저장소에 offload 가능

 

 

React쪽에서 많이 사용하는 상태관리 방법중에 

거의 설정 필요 없이 바로 사용 가능. 작지만 유연한 구조에 딱! 인 녀석이 Zustand입니다.

 

 

Zustand

 

 

 

 

 

Zustand + 서버 캐싱 조합

// useWorkStore.ts
import { create } from 'zustand';

interface Work {
  id: string;
  title: string;
}

interface WorkStore {
  works: Record<string, Work>;
  setWorks: (works: Work[]) => void;
}

export const useWorkStore = create<WorkStore>((set) => ({
  works: {},
  setWorks: (list) =>
    set({
      works: Object.fromEntries(list.map((w) => [w.id, w])),
    }),
}));

 

이러면:

전역 상태 관리

필요한 데이터만 접근

컴포넌트 리렌더 최소화

 

 

✨ 결론

Works 데이터를 전역으로 관리해도 메모리 문제는 거의 없음,

데이터가 너무 크거나, 빈번하게 바뀌거나, 전체 리렌더를 유발하는 구조라면 성능 최적화 필요.

Zustand, Redux Toolkit, React Query 조합을 잘 쓰면 아주 효율적으로 관리 가능

 

 

 Zustand가 인기 많은 이유

 

장점 설명
심플한 API create() 하나로 상태 만들고 끝. boilerplate 거의 없음
Redux보다 가볍고 직관적 action, reducer, slice 다 필요 없음
부분 상태 구독 가능 리렌더 최적화가 자동으로 됨 (성능 굿)
TypeScript 친화적 타입 추론 잘 되고, 구조도 깔끔
서버 상태와도 궁합 좋음 React Query, SWR 등과 같이 쓰기 쉬움
중간 규모 프로젝트에 딱 복잡하지 않으면서 강력함

 

 

실제 사용하는 곳들

Vercel (Zustand 만든 팀)

T3 Stack (Next.js + TypeScript + Tailwind + Zustand + Prisma)

커뮤니티 기반 SaaS, 사이드 프로젝트 등에서 널리 사용됨

 

 

 

프로젝트 규모 Zustand 적합성
소규모/사이드 프로젝트 👍 아주 적합
중간 규모 SaaS 👍 훌륭함
대규모 기업 프로젝트 👍 가능하지만, 팀의 스타일에 따라 Redux 선호할 수도
글로벌 상태가 많지 않은 앱 ✅ 가볍게 도입 가능

 

비교

항목 Zustand Redux Toolkit Context + useReducer
코드 간결함 ✅ 매우 심플 ❌ 비교적 장황함 ⚠️ 구조화 필요
전역 상태 관리 ✅ 가능 ✅ 아주 강력 ⚠️ 퍼포먼스 이슈 가능
리렌더 최적화 ✅ 기본 내장 ⚠️ 직접 memoization 필요 ❌ 전체 리렌더 발생 가능
타입스크립트 ✅ 굿 ✅ 굿 ⚠️ 직접 타입 정의 많음
학습 난이도 ⭐ 쉬움 ❌ 중간 이상 ⭐ 쉬움

 

정리

Zustand는 2024~2025 기준으로 가장 많이 쓰이는 경량 상태 관리 라이브러리 중 하나임

복잡한 Redux 셋업 없이도 전역 상태를 깔끔하게 다룰 수 있고, 성능도 아주 좋음.

 

 

 

설치하기

npm install zustand

 

 

적용하기

Folder 구조

src/
  features/
    works/
      repositories/
        WorkRepository.ts
      stores/
        useWorkStore.ts
      model/
        work.ts

 

 

WorkRepository.ts (함수형)

// features/works/repositories/WorkRepository.ts
import { supabase } from '../../../common/supabase';
import { table } from '../../../common/config/configstring';
import { Work, WorkView } from '../model/work';

export const WorkRepository = {
  async getList(): Promise<WorkView[]> {
    const { data, error } = await supabase.from(table.WORK_VIEW).select('*');
    if (error) console.error('getList error:', error);
    return data ?? [];
  },

  async getListByAssigneeId(assignee: string): Promise<WorkView[]> {
    const { data, error } = await supabase
      .from(table.WORK_VIEW)
      .select()
      .eq('assignee', assignee);
    if (error) console.error('getListByAssigneeId error:', error);
    return data ?? [];
  },

  async getCountByAssigneeId(assignee: string): Promise<number> {
    const { count, error } = await supabase
      .from(table.WORK_VIEW)
      .select('*', { count: 'exact' })
      .eq('assignee', assignee)
      .limit(0);
    if (error) console.error('getCountByAssigneeId error:', error);
    return count ?? 0;
  },

  async getListByFilter(filter: string, offset = 0, cnt = 10): Promise<{ v: WorkView[]; total: number }> {
    const { data, count } = await supabase
      .from(table.WORK_VIEW)
      .select('*', { count: 'estimated' })
      .or(filter)
      .range(offset, offset + cnt);
    return { v: data ?? [], total: count ?? 0 };
  },

  async getById(id: number): Promise<WorkView | null> {
    const { data, error } = await supabase
      .from(table.WORK_VIEW)
      .select()
      .eq('id', id);
    if (error) console.error('getById error:', error);
    return data?.[0] ?? null;
  },

  async insert(work: Work): Promise<Work | null> {
    const { data, error } = await supabase
      .from(table.WORKS)
      .insert(work)
      .select();
    if (error) console.error('insert error:', error);
    return data?.[0] ?? null;
  },

  async update(work: Work): Promise<Work | null> {
    const { data, error } = await supabase
      .from(table.WORKS)
      .update(work)
      .eq('id', work.id)
      .select();
    if (error) console.error('update error:', error);
    return data?.[0] ?? null;
  },

  async delete(id: number): Promise<void> {
    const { error } = await supabase.from(table.WORKS).delete().eq('id', id);
    if (error) console.error('delete error:', error);
  },
};

 

 

useWorkStore.ts (Zustand)

// features/works/stores/useWorkStore.ts
import { create } from 'zustand';
import { Work, WorkView } from '../model/work';
import { WorkRepository } from '../repositories/WorkRepository';

interface WorkState {
  works: WorkView[];
  selectedWork: WorkView | null;
  totalCount: number;
  loading: boolean;

  fetchWorks: () => Promise<void>;
  fetchWorksByAssignee: (assignee: string) => Promise<void>;
  fetchWorksByFilter: (filter: string, offset?: number, cnt?: number) => Promise<void>;
  fetchWork: (id: number) => Promise<WorkView | null>;

  createWork: (work: Work) => Promise<Work | null>;
  updateWork: (work: Work) => Promise<Work | null>;
  deleteWork: (id: number) => Promise<void>;
}

export const useWorkStore = create<WorkState>((set) => ({
  works: [],
  selectedWork: null,
  totalCount: 0,
  loading: false,

  fetchWorks: async () => {
    set({ loading: true });
    const data = await WorkRepository.getList();
    set({ works: data, loading: false });
  },

  fetchWorksByAssignee: async (assignee: string) => {
    set({ loading: true });
    const data = await WorkRepository.getListByAssigneeId(assignee);
    set({ works: data, loading: false });
  },

  fetchWorksByFilter: async (filter, offset = 0, cnt = 10) => {
    set({ loading: true });
    const { v, total } = await WorkRepository.getListByFilter(filter, offset, cnt);
    set({ works: v, totalCount: total, loading: false });
  },

  fetchWork: async (id: number) => {
    const work = await WorkRepository.getById(id);
    set({ selectedWork: work });
    return work;
  },

  createWork: async (work: Work) => {
    const newWork = await WorkRepository.insert(work);
    return newWork;
  },

  updateWork: async (work: Work) => {
    const updated = await WorkRepository.update(work);
    return updated;
  },

  deleteWork: async (id: number) => {
    await WorkRepository.delete(id);
  },
}));

 

 

 

사용 예시

const { works, fetchWorks, loading } = useWorkStore();

useEffect(() => {
  fetchWorks();
}, []);

return loading ? <p>Loading...</p> : <ul>{works.map(w => <li key={w.id}>{w.title}</li>)}</ul>;

 

 

 

# 해피코딩 !!

반응형

 

1. 지형정보 가져오기

Leaflet 을 사용할때 layer는 보통 geojson을 사용하게 됩니다.

 

지형이나 특정 지역을 표시할때, geojson을 구해서 사용해야 하는데, OSM( open street map)을 이용하면, 이미 만들어진 지역의 정보를 구할수 있습니다. 

https://www.openstreetmap.org/#map=19/37.250567/127.078423

 

오픈스트리트맵

오픈스트리트맵 (OpenStreetMap)은 여러분과 같은 사람들이 만들어, 개방형 라이선스에 따라 자유롭게 사용할 수 있는 세계 지도입니다.

www.openstreetmap.org

 

open street map 접속하기

내보내기

 

OSM file 이 만들어집니다.

 

OSM 파일에는 해당 영역의 모든 데이터가 있습니다.

 

2.osm to geojson(OSM 파일을 geojson으로 바꾸기)

OSM 파일을 geojson으로 변경을 위해서는 이를 지원하는 서비스를 이용하거나 아니면 코드로 작성해야 겠죠..^^ (당연한 이야기죠. )

 

https://mygeodata.cloud/

 

MyGeodata Converter | MyGeodata Cloud

--> --> Uploaded Files Type Size Please note that your data will not be shared to anybody. Recently used data is your data that you have recently uploaded and can only be seen by you from your computer and your web browser. You can reuse them for a repeat

mygeodata.cloud

여기에서OSM 파일을 geojson으로 변경이 가능합니다.

그러나 가격 부담 ㅠ_ㅠ

 

 

그래서 저는 직접 만드는 쪽으로 선회했습니다. ^^

 

import codecs
import json
import osm2geojson

# 각 feature에 bbox 추가
def add_bbox_to_features(geojson):
    for feature in geojson['features']:
        geom = feature.get('geometry')
        if not geom:
            continue
        coords = geom.get('coordinates')

        def extract_coords(c):
            if isinstance(c[0], (float, int)):  # Point
                yield c
            else:
                for sub in c:
                    yield from extract_coords(sub)

        min_lat = min_lon = float('inf')
        max_lat = max_lon = float('-inf')

        for lon, lat in extract_coords(coords):
            min_lon = min(min_lon, lon)
            min_lat = min(min_lat, lat)
            max_lon = max(max_lon, lon)
            max_lat = max(max_lat, lat)

        feature['bbox'] = [min_lon, min_lat, max_lon, max_lat]

# OSM 파일 읽기 및 변환
with codecs.open('sample.osm', 'r', encoding='utf-8') as data:
    xml = data.read()

geojson = osm2geojson.xml2geojson(xml, filter_used_refs=False, log_level='INFO')

# feature 단위 bbox 추가
add_bbox_to_features(geojson)

# 저장
with open("result.json", "w", encoding="utf-8") as f:
    json.dump(geojson, f, ensure_ascii=False, indent=2)

 

 

osm2geojson이라는 python package가 있는데 이를 활용하여 간단하게 만들수 있습니다.

(bbox는 사실 필요 없는데, 저는 bbox 활용할 일이 있어서 추가 작성 했습니다.)

 

osm2geojson 예제에 text encoding 관련된 부분에 한글이 고려 안되어있는 부분이 있습니다. 그래서 unicode 텍스트 (이거 뭐랄까 ascii로 unicode를 하나하나 출력) 출력되는데, 이부분 주의가 필요합니다.

with open("result.json", "w", encoding="utf-8") as f:
    json.dump(geojson, f, ensure_ascii=False, indent=2)

 

아무튼 결과물은 다음과 같이 나오게 됩니다.

결과물 (일부만)

{
      "type": "Feature",
      "properties": {
        "type": "way",
        "id": 60274279,
        "tags": {
          "leisure": "park",
          "name": "반달공원",
          "name:en": "Bandal Park",
          "name:ko": "반달공원"
        },
        "nodes": [
          522283226,
          804659125,
          522283225,
          522283224,
          522283223,
          522283222,
          522283221,
          522283220,
          522283219,
          804658865,
          522283218,
          749481489,
          12597050520,
          1041086129,
          522283226
        ],
        "timestamp": "2025-02-17T23:25:53Z",
        "user": "VLD297",
        "uid": 22440181,
        "version": 6
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              127.0788144,
              37.2516044
            ],
            [
              127.0790588,
              37.2514582
            ],
            [
              127.0792253,
              37.251231
            ],
            [
              127.0792854,
              37.2509749
            ],
            [
              127.0792393,
              37.2507596
            ],
            [
              127.0791239,
              37.2505404
            ],
            [
              127.0786913,
              37.250087
            ],
            [
              127.0784826,
              37.2499406
            ],
            [
              127.0782648,
              37.2498577
            ],
            [
              127.077969,
              37.2498236
            ],
            [
              127.0776801,
              37.2498829
            ],
            [
              127.0773679,
              37.2500504
            ],
            [
              127.0777277,
              37.2504259
            ],
            [
              127.0780778,
              37.250814
            ],
            [
              127.0788144,
              37.2516044
            ]
          ]
        ]
      },
      "bbox": [
        127.0773679,
        37.2498236,
        127.0792854,
        37.2516044
      ]
    },

 

이렇게 나온 geojson을 leaflet 을 이용하여 layer로 추가하면 멋진 커스터마이징이 가능해지죠!!

 

 

# 해피코딩!!

'Node.js , React, Docker' 카테고리의 다른 글

[Typescript] 한글 조사 처리  (2) 2025.04.09
[react] zustand 이용한 store-repository 구조  (0) 2025.03.27
[React] OSM :MAP Tile Server  (0) 2025.03.24
[Docker] NginX docker 환경 만들기  (0) 2024.12.24
[React] Components  (0) 2024.09.07
반응형

 

OSM : Open Street Map

https://planet.openstreetmap.org/

 

Planet OSM

Supporting OSM OSM data is free to use, but is not free to make or host. The stability and accuracy of OSM.org depends on its volunteers and donations from its users. Please consider making an annual recurring gift to OSM to support the infrastructure, too

planet.openstreetmap.org

 

 

구글 맵, 다음 지도, 네이버 맵등을 이용해서 지도 정보를 화면에 출력할 수도 있지만, OSM(Open Street Map)을 이용해보고자 합니다.

(뭔가 더 자유도가 있는 것 같음..)

 

 

OSM 은 우선 사용하는데에는 무료 입니다.

OSM는 어떻게 무료인가요?

OpenStreetMap은 크라우드소싱으로 만들어진 오픈 데이터베이스

ODbL(Open Database License) 하에 무료로 사용할 수 있습니다.

누구든지 상업/비상업 목적으로 자유롭게:

데이터를 보고,

복사하고,

수정하고,

앱/웹에서 사용할 수 있어요.

 

하지만 다음은 꼭 주의하세요

항목설명

🔌 타일 서버 (tile.openstreetmap.org) OSM 데이터는 무료지만 기본 타일 서버는 “공공 기여 기반”이라 과도한 사용 금지
📈 상업적 서비스 웹사이트/앱에서 많은 트래픽이 예상되면 타일 서버를 직접 운영하거나 외부 제공업체(MapTiler 등)를 사용해야 함
📝 저작권 표시 필수 지도에 “© OpenStreetMap contributors” 표기 필요
💥 Rate Limit 기본 서버는 과도한 호출 시 차단당할 수 있음 (특히 앱에서 다수 사용자일 경우)

 

 

 대안 서비스 (타일 서버 대체용)

서비스설명

MapTiler 상업적 사용 OK, 다양한 스타일 제공
OpenMapTiles 자체 호스팅 가능, OSM 기반
Carto 지도 + 데이터 시각화 전문
Mapbox 고성능 상업용 지도 SDK (유료 요금제 있음)

 

 

 

 

실무 예시

작은 규모의 내부 대시보드나 개인 프로젝트 → tile.openstreetmap.org 사용 OK

상업 서비스, 앱 배포, 사용자 많은 시스템 → 별도 타일 서버나 상용 서비스 이용 권장

 

 

OSM 타일 서버 직접 구축하는 법

도구설명

TileServer GL 벡터/래스터 타일 서버, Docker로 간편 구축 가능
Tegola Go 기반 고성능 벡터 타일 서버
openmaptiles.org 미리 생성된 벡터 타일 다운로드 or Docker 배포

 

 

타일 서버 구축

1. 프로젝트 디렉토리 구성

osm-tileserver/
├── docker-compose.yml
└── data/
    └── south-korea.mbtiles   ← 원하는 지역 타일 파일

 

2. docker-compose.yml

 

version: "3"

services:
  tileserver:
    image: klokantech/tileserver-gl
    ports:
      - "8080:80"
    volumes:
      - ./data:/data
    environment:
      - MAPBOX_STYLES=local

 

3. 실행 방법

# 프로젝트 폴더로 이동
cd osm-tileserver

# 실행
docker-compose up -d

 

 

 

4. 접속 확인

 

브라우저에서 접속: http://localhost:8080

 

제공 기능:

웹 기반 지도 뷰어

벡터 타일 (PBF)

래스터 PNG 타일 (/styles/basic/{z}/{x}/{y}.png)

Leaflet/OpenLayers 연동용 URL 자동 제공

 

5. Leaflet 연동 예시

L.tileLayer('http://localhost:8080/styles/basic/{z}/{x}/{y}.png', {
  maxZoom: 18,
  attribution: '© OpenStreetMap contributors'
}).addTo(map);

 

 

.mbtiles 파일은 어디서 받나요?

https://openmaptiles.org/downloads/

대한민국: south-korea.mbtiles 다운로드

용량 수백 MB ~ 수 GB

 

 

6. OSM file을 geojson 으로 변경하기

OSM 맵의 특정 부분을 geojson으로 변경해서 사용하고 싶을 때가 있습니다.

특정 영역의 색상을 표시한다거나 할때, 지도상에서 해당 영역을 찾아서 표시 하고 싶을 때가 있죠.

 

 

# 해피코딩 !!

 

 

 

 

반응형

NginX 를  현재 서버에 설치해서 사용하는 경우, 서버의 이곳 저곳에 nginx 관련 정보들이 흩어져 있게 됩니다.

Docker로 설정할때 어려운 부분들이죠.

이를 한번 정리해보고자합니다.

 

 

0. 우선 nginx container를 하나 생성

docker run -d --name tmp-nginx nginx

 

 

docker cp 명령어를 사용하여 container의 /etc/nginx/nginx.conf 파일을 현재 프로젝트 폴더의 ./nginx/nginx.conf 로 옮긴다.

 

1. nginx.conf 

docker cp tmp-nginx:/etc/nginx/nginx.conf ./nginx/nginx.conf

 

 

2. config.d

docker cp tmp-nginx:/etc/nginx/conf.d ./nginx

 

 

docker-compose 파일 작성하기

services:
  api_gateway:
    image: nginx
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/conf.d/:/etc/nginx/conf.d
    ports:
      - 8080:80
  mywebserver:
    build: ./mywebserver
  myapiserver:
    build: ./myapiserver

 

 

 

 

 

Tip

1. Docker-Compose 는 어디에 있나?

docker desktop을 설치하고 나서 docker-compose 를 찾으려고 하면 안찾아져요.

이유는 path가 안걸려 있어서 그래요.

mac에서 보면 docker와 compose 의 위치가 상이합니다. (왜 이렇게 해놨는지는... 저도잘..)

docker: /Applications/Docker.app/Contents/Resources/bin/docker

docker-compose: /Applications/Docker.app/Contents/Resources/cli-plugins/docker-compose

 

아무튼 그래서 docker-compose를 terminal에서 실행하려면, PATH에 추가해주는 것이 좋겠죠.

export PATH="~~~~:/Applications/Docker.app/Contents/Resources/bin:/Applications/Docker.app/Contents/Resources/cli-plugins:$PATH"

 

windows나 linux는 또다른 위치 입니다.

[Ubuntu]

docker-compose: usr/lib/docker/cli-plugins/docker-compose

docker: /usr/bin/docker /usr/lib/docker /etc/docker /usr/local/bin/docker /usr/libexec/docker

 

2. Dockerfile 에서 npm build 시 error 발생하면 바로 볼수 있는 방법

 

RUN npm run build || cat npm-debug.log

 

'Node.js , React, Docker' 카테고리의 다른 글

[React] OSM : 지형 정보 가져오기(export)  (4) 2025.03.24
[React] OSM :MAP Tile Server  (0) 2025.03.24
[React] Components  (0) 2024.09.07
[AWS] 여러가지 알아야 할것들  (3) 2024.07.12
Docker 간단히 이해하기  (0) 2024.07.11
반응형

 

Nivo 

https://nivo.rocks/components/

 

Components | nivo

 

nivo.rocks

 

 

 

 

Google Fonts

https://fonts.google.com/

 

Browse Fonts - Google Fonts

Making the web more beautiful, fast, and open through great typography

fonts.google.com

 

 

 

 

MUI

 

https://mui.com/

 

MUI: The React component library you always wanted

MUI provides a simple, customizable, and accessible library of React components. Follow your own design system, or start with Material Design.

mui.com

 

'Node.js , React, Docker' 카테고리의 다른 글

[React] OSM :MAP Tile Server  (0) 2025.03.24
[Docker] NginX docker 환경 만들기  (0) 2024.12.24
[AWS] 여러가지 알아야 할것들  (3) 2024.07.12
Docker 간단히 이해하기  (0) 2024.07.11
[Docker] proxy 문제 해결  (0) 2021.11.11
반응형

 

 

 

 

 VPC의 구성

VPC(Virtual Private Cloud)는 AWS의 사용자 젖용 가상 네트워크 입니다.

각 지역별 리즌들이 있고 이 리즌 내에 VPC를 구성 하는 것이죠.

 

 

 

VPC내에 하나 이상의 서브넷을 구성할 수 있습니다.

기본 VPC는 Amazon VPC를 사용하기 시작하는 경우 각 AWS 리전에 기본 VPC가 있습니다. 기본 VPC는 각 가용 영역의 퍼블릭 서브넷, 인터넷 게이트웨이 및 DNS 확인 활성화 설정과 함께 제공됩니다. 따라서 기본 VPC로 Amazon EC2 인스턴스를 즉시 시작할 수 있습니다. 기본 VPC에서 Elastic Load Balancing, Amazon RDS, Amazon EMR 같은 서비스를 사용할 수도 있습니다.

 

VPC를 생성할 경우

다음 절차에 따라 Virtual Private Cloud(VPC)를 생성합니다. VPC에서 AWS 리소스를 생성하려면 먼저 VPC에 서브넷, 라우팅 테이블, 게이트웨이와 같은 추가 리소스가 있어야 합니다

 

 

 

ECS

 

 

 

ECS 는 docker 와 달리 bridge network 를 기본 사용하지 않습니다.
host network 를 사용합니다.
즉, 하나의 Task Definition 에서 정의된 컨테이너들은 동일한 EC2 내에 호스트 네트워크를 그대로 사용한합니다.
따라서 localhost 로 컨테이너간 통신이 가능합니다.

 

실행 에러 exec format error

 

만약 실행시 위와 같은 에러가 발생했다면 아마 나처럼 M1, M2 macOS 를 사용중일 것입니다.
AWS 도 차츰 arm 아키텍처를 적극지원하지만, 아직은 대다수의 환경이 amd64(intel) 로 되어 있는 것은 어쩔 수없습니다.

원인
docker image build 는 M1 (arm64) 에서 했기 때문에 arm64 이미지를 생성한 상태고, ECS Fargate 아키텍쳐는 x86_64 (amd64) 기 때문입니다.
즉 이미지를 만든 provider와 task executor 실행 환경이 다르기 때문에 발생한 문제입니다.

'Node.js , React, Docker' 카테고리의 다른 글

[Docker] NginX docker 환경 만들기  (0) 2024.12.24
[React] Components  (0) 2024.09.07
Docker 간단히 이해하기  (0) 2024.07.11
[Docker] proxy 문제 해결  (0) 2021.11.11
REST API  (0) 2017.06.20

+ Recent posts