1. EC2 서버 접속

sudo nano /etc/nginx/nginx.conf

 

 

 

2. http 블록에 client_max_body_size 설정 추가

 

 

ctrl + o -> Enter

 

sudo nginx -t   # 설정 문법 확인
sudo systemctl reload nginx   # 설정 반영 (혹은 restart)

 

'Linux' 카테고리의 다른 글

Ubuntu  (0) 2025.02.12
AWS EC2의 Ubuntu 서버에 Docker 설치  (0) 2025.02.12

애드블락 내 필터 목록에 

||reserve.insiseol.or.kr/comm/js/devtools-detector.js 추가

GitHub Actions에서 SHA를 사용하여 Docker 이미지 태그를 설정하는 과정은 CI/CD 파이프라인에서 특정 커밋에 대한 이미지 버전을 추적할 수 있도록 해줍니다. 이 방법을 사용하면 어떤 코드 상태에서 빌드된 이미지인지를 쉽게 파악할 수 있습니다.

1. SHA 가져오기

GitHub Actions에서 현재 커밋의 SHA-1 해시 값을 가져오는 코드

- name: Set GIT SHA Short 
  id: sha
  run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
  • git rev-parse --short HEAD: 현재 커밋의 SHA-1 해시 값을 7자리로 축약하여 가져옵니다.
  • sha_short=$(git rev-parse --short HEAD): 이 값을 sha_short 변수에 저장합니다.
  • $GITHUB_OUTPUT: GitHub Actions에서 이후의 단계에서 이 값을 사용할 수 있도록 설정합니다.

2. SHA를 Docker 이미지 태그로 사용

현재 커밋 SHA 값을 사용하여 Docker 이미지 태그를 설정하는 코드

IMAGE_TAG: ${{ steps.sha.outputs.sha_short }}-testing​
  • IMAGE_TAG: Docker 이미지의 태그를 현재 커밋 SHA 값으로 설정합니다. sha_short 값을 사용하여 태그가 abc1234-testing 형식으로 만들어집니다.

3. Docker 이미지 빌드 및 푸시

이후, Docker 이미지를 빌드하고 ECR에 푸시

docker build -f Dockerfile-testing -t my-ecr-repo/my-image:$IMAGE_TAG .
docker push my-ecr-repo/my-image:$IMAGE_TAG
  • my-ecr-repo/my-image:abc1234-testing: Docker 이미지의 이름과 태그가 커밋 SHA 기반으로 설정됩니다.

도커 이미지 이름과 태그

  • 이미지 이름: 도커 이미지 이름은 고유한 식별자로, dockerhub나 ECR에 저장된 이미지를 식별합니다.
    • 예시: my-image
  • 이미지 태그: 해당 이미지의 버전이나 상태를 구분하는 식별자로 사용됩니다. 보통 버전 번호(예: 1.0, latest, v2)나 커밋 SHA(예: abc1234)를 사용합니다.
    • 예시: my-image:latest, my-image:v1.0, my-image:abc1234-testing

왜 태그가 중요한가?

  • 버전 관리: 동일한 이미지 이름을 사용하면서 다양한 버전이나 상태를 관리할 수 있습니다. 예를 들어, my-image:v1과 my-image:v2는 같은 이미지 이름이지만 다른 버전을 나타냅니다.
  • CI/CD에서 버전 추적: CI/CD 파이프라인에서 커밋 SHA를 태그로 사용하면 특정 커밋에서 빌드된 이미지를 추적할 수 있습니다.
  • 롤백과 배포 관리: 문제가 발생하면 이전에 잘 동작했던 이미지를 태그를 통해 롤백하거나 배포 상태를 확인할 수 있습니다.

1. 우분투 (Ubuntu)

우분투는 리눅스 기반의 운영체제입니다. 우분투는 리눅스 커널을 기반으로 하며, 디베인(Debian)을 기반으로 한 리눅스 배포판입니다. 우분투는 사용자가 리눅스를 손쉽게 설치하고 사용할 수 있도록 필요한 소프트웨어와 도구들을 한데 묶어서 배포한 운영체제입니다.

  • 그래픽 인터페이스(GUI)를 제공하며, 데스크탑에서 사용하기 매우 직관적입니다. 사용자는 우분투를 통해 다양한 소프트웨어를 쉽게 설치하고 관리할 수 있습니다.
  • 우분투는 사용자 친화적인 환경을 제공하며, 초보자부터 고급 사용자까지 모두 사용하기 적합한 리눅스 배포판입니다.
  • 우분투는 서버 환경에서도 널리 사용되지만, 특히 데스크탑 환경에서 많이 사용됩니다.

우분투에서 패키지 관리 시스템은 APT(Advanced Package Tool)를 사용합니다. apt는 패키지 설치, 업그레이드, 제거 등을 간편하게 할 수 있는 도구입니다. 우분투는 디베인에서 제공하는 패키지들과 함께 더 많은 사용자 친화적인 도구를 제공합니다.

2. 디베인 (Debian)

디베인(Debian)은 리눅스 배포판 중 하나로, 우분투기반이 되는 운영체제입니다. 디베인은 리눅스 커널을 기반으로 하여 시스템과 프로그램들을 관리하는 역할을 합니다. 주로 서버 환경에서 많이 사용되며, 안정성과 보안성을 우선시합니다.

  • 디베인은 기본적으로 가벼운 환경을 제공하고, 주로 수동 설정고급 사용자를 위해 설계되었습니다.
  • 디베인은 우분투보다 더 많은 커스터마이징을 제공하며, 필요에 따라 필요한 패키지들만 설치할 수 있습니다.
  • 안정성을 중요시하는 서버 환경에서 디베인이 많이 사용됩니다.

디베인도 apt를 사용하여 패키지 관리 시스템을 운영합니다. apt는 디베인에서 제공하는 모든 패키지를 설치하고 관리하는 데 사용됩니다.

3. 우분투와 디베인의 관계

  • 우분투디베인을 기반으로 한 리눅스 배포판입니다. 즉, 우분투는 디베인에서 파생되어 개발된 운영체제입니다.
  • 디베인은 더 안정적이고 최소화된 배포판으로, 주로 서버 환경에서 사용됩니다.
  • 우분투는 디베인을 기반으로 그래픽 환경을 추가하고, 사용자 친화적인 도구와 기능을 더 많이 제공하여 데스크탑 환경에서 더욱 인기가 있습니다.

4. APT (Advanced Package Tool)

apt는 리눅스 배포판에서 패키지 관리 시스템을 다루는 도구입니다. 우분투와 디베인 모두 apt를 사용하여 패키지를 설치하고 관리합니다. apt는 패키지를 다운로드, 설치, 업데이트, 삭제하는 데 매우 유용한 명령어들을 제공합니다.

  • 패키지 설치: apt install [패키지명]
  • 패키지 업데이트: apt update (패키지 목록을 최신 상태로 업데이트)
  • 패키지 업그레이드: apt upgrade (설치된 패키지들의 최신 버전으로 업그레이드)
  • 패키지 제거: apt remove [패키지명]
  • 패키지 정보 확인: apt show [패키지명]

쉽게 말하자면 macOS의 homebrew 비슷한 것 패키지 관리자

5. 우분투와 디베인 요약

  • 우분투디베인을 기반으로 하여, 사용자가 쉽게 설치하고 사용할 수 있는 리눅스 운영체제입니다.
  • 디베인서버고급 사용자를 위한 안정성보안성을 중시하는 리눅스 배포판입니다.
  • 우분투는 디베인에서 제공하는 기능을 기반으로 그래픽 환경과 사용자 친화적인 도구들을 추가하여 데스크탑 환경에서 유용하게 사용됩니다.
  • 두 배포판 모두 APT 패키지 관리 시스템을 사용하여 패키지 관리를 편리하게 할 수 있습니다.

'Linux' 카테고리의 다른 글

413 RequestEntity Too Large  (0) 2025.04.08
AWS EC2의 Ubuntu 서버에 Docker 설치  (0) 2025.02.12

Docker 설치

1. 패키지 목록 업데이트:

sudo apt-get update

 

2. 필수 패키지 설치:

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

 

3. Docker의 공식 GPG 키 추가:

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

curl:  Client URL의 약자로, 네트워크를 통해 데이터를 전송하거나 다운로드할 수 있는 명령어입니다. HTTP, HTTPS, FTP, SFTP 등 다양한 프로토콜을 지원하며, 파일을 다운로드하거나 API 요청을 보내는 등의 작업을 할 수 있습니다.

주요 기능은 웹 서버와 통신하거나 인터넷에서 데이터를 다운로드/업로드하는 데 사용됩니다. 예를 들어, 웹사이트에서 데이터를 가져오거나, 파일을 서버에 업로드하는 등의 작업을 할 수 있습니다.

 

4. Docker 저장소 추가:

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

 

5. 패키지 목록 다시 업데이트:

sudo apt-get update

 

 

6. Docker CE 설치:

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

 

 

7. Docker 서비스 시작 및 부팅 시 자동 시작 설정:

sudo systemctl start docker
sudo systemctl enable docker

 

 

8. 현재 사용자를 Docker 그룹에 추가하여 sudo 없이 Docker 명령어 실행 가능하게 설정:

sudo usermod -aG docker ${USER}

기본적으로 Ubuntu 운영체제를 설치한 EC2 인스턴스에서는 사용자 계정이 ubuntu로 생성되므로 아래와 같이 하면 적용됨

sudo usermod -aG docker ubuntu

 

이후, 변경 사항을 적용하려면 현재 세션을 종료하고 다시 로그인

 

+ 현재 로그인한 사용자 이름을 확인하는 법

whoami

 

9. Docker 설치 확인:

docker --version

 

Docker Compose 설치

1. docker compose 설치:

sudo curl -L "https://github.com/docker/compose/releases/download/$(curl -s https://api.github.com/repos/docker/compose/releases/latest | jq -r .tag_name)/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

 

chmod: 파일이나 디렉터리의 권한을 변경하는 명령어입니다. 'change mode'의 줄임말로, 파일 시스템에서 사용자가 파일이나 디렉터리의 접근 권한을 수정할 수 있게 해줍니다.

리눅스나 유닉스 계열 운영체제에서는 파일에 대해 읽기(Read), 쓰기(Write), 실행(Execute) 권한을 설정할 수 있습니다. chmod 명령어는 이 권한을 수정하는 데 사용됩니다.

파일 권한의 기본 개념

리눅스에서 파일 권한은 소유자(owner), 그룹(group), 기타(others) 세 가지 범위로 나누어져 있습니다. 각 범위마다 읽기(r), 쓰기(w), 실행(x) 권한을 설정할 수 있습니다.

chmod 명령어의 사용법

  1. 문자 형태 (기호 형태): 권한을 기호로 지정하여 변경할 수 있습니다.
    • r: 읽기 권한
    • w: 쓰기 권한
    • x: 실행 권한
    • +: 권한 추가
    • -: 권한 제거
    • =: 권한 설정

즉, sudo chmod +x /usr/local/bin/docker-compose 명령어는 /usr/local/bin/docker-compose 파일에 실행 권한을 추가하는 명령입니다.

 

2. 설치 확인:

docker-compose --version

'Linux' 카테고리의 다른 글

413 RequestEntity Too Large  (0) 2025.04.08
Ubuntu  (0) 2025.02.12
<Placemark>
  <name>Dongdaemun Dakhanmari</name>
  https://mymaps.usercontent.google.com/hostedimage/m/*/3AEDAZkrA_VWSvnhW2PkyBnuKwRcY5POk9b0GkJPBt6jJP9PrFv5PdpE-gfu64lpu9fdzhSp1AcXhrb9iNJtAJHp3U6XhJHpieYpWHv19IMs-3v_7WoPZOm3j7p70JO9h1kkti0PCZyDa5vLMzqzivXQoHqYBDoYT0NTUsbSb1wOa4WU8ceC36p7JVwi3GW1PSML9Ap_o1oL-F_pL?authuser=0&fife=s16383" height="200" width="auto" />

PIC]]>
  <styleUrl>#icon-1899-DB4436</styleUrl>
  <ExtendedData>
    <Data name="gx_media_links">
      https://mymaps.usercontent.google.com/hostedimage/m/*/3AEDAZkrA_VWSvnhW2PkyBnuKwRcY5POk9b0GkJPBt6jJP9PrFv5PdpE-gfu64lpu9fdzhSp1AcXhrb9iNJtAJHp3U6XhJHpieYpWHv19IMs-3v_7WoPZOm3j7p70JO9h1kkti0PCZyDa5vLMzqzivXQoHqYBDoYT0NTUsbSb1wOa4WU8ceC36p7JVwi3GW1PSML9Ap_o1oL-F_pL?authuser=0&fife=s16383]]>
    </Data>
  </ExtendedData>
  <Point>
    <coordinates>
      101.6602995,3.176526,0
    </coordinates>
  </Point>
</Placemark>

Dongdaemun Dakhanmari

    <coordinates>
      101.6602995,3.176526,0
    </coordinates>

KLCC #A1 @1

정규화(Normalization)

정규화는 중복을 줄이고, 데이터의 일관성과 무결성을 유지하기 위해 데이터를 여러 개의 테이블로 나누는 과정입니다. 이 과정에서 각 테이블은 단일 책임을 가지며, 데이터 중복을 최소화합니다.

  • 예를 들어, 가게 정보, 상품 정보, 주문 정보가 있을 때, 각 정보는 별도의 테이블로 분리되며, 가게상품은 각자 독립적으로 관리됩니다.
  • 필요한 데이터는 조인을 통해 가져오며, 각 테이블이 가진 정보는 중복 없이 잘 정리되어 있습니다.

정규화의 특징:

  • 중복되는 데이터가 적음.
  • 데이터 수정 시 한 곳에서만 수정하면 되므로 일관성이 유지됩니다.
  • 여러 테이블을 조인해야 하므로 조회 성능이 떨어질 수 있습니다.

정리하자면, 정규화여러 테이블을 만들고 조인하여 필요한 데이터를 가져오는 방식입니다. 이때 중복 데이터가 없기 때문에 저장 공간을 절약하고, 데이터 무결성을 유지할 수 있습니다.

 

예시)

  • 가게 정보상품 정보를 각각 별도의 테이블로 만들고, 그때그때 필요한 상품과 가게의 관계를 조인을 통해 조회합니다.
    • 예) Store 테이블, Product 테이블
    • 필요한 정보가 있을 때, Store 테이블과 Product 테이블을 조인해서 가져옵니다.

이렇게 정규화를 사용하면 데이터의 일관성을 유지하고, 저장 공간을 절약할 수 있지만, 조회 성능에서는 조인으로 인해 약간의 비용이 발생할 수 있습니다

 

 

 

역정규화(Denormalization)

역정규화는 조회 성능을 개선하기 위해 일부러 데이터를 중복 저장하는 방식입니다. 데이터베이스 설계에서 중복을 허용하고, 이를 통해 읽기 성능을 향상시킬 수 있습니다. 중복된 데이터를 일부 테이블에 저장하는 대신 조인 없이 한 번의 조회로 필요한 정보를 가져올 수 있습니다.

  • 예를 들어, 가게 정보상품 정보가 모두 포함된 하나의 테이블을 만들어 두 개의 테이블을 조인하지 않고도 조회가 가능하도록 하는 방식입니다.
  • 이렇게 하면 조회할 때 조인이 필요 없으므로 성능이 향상됩니다. 하지만 중복된 데이터가 발생하여 데이터 수정 시 여러 곳에서 수정이 필요하고, 저장 공간이 더 많이 필요할 수 있습니다.

역정규화의 특징:

  • 데이터 중복이 발생하여 저장 공간이 늘어납니다.
  • 읽기 성능이 향상되며, 조인 없이 데이터를 빠르게 조회할 수 있습니다.
  • 데이터 수정 시 여러 테이블에서 변경을 해야 하므로 관리가 복잡해질 수 있습니다.

 

정리

  • 정규화(Normalization): 여러 개의 테이블로 데이터를 나누어 중복을 최소화하고, 조인을 통해 데이터를 조회하는 방식.
  • 역정규화(Denormalization): 일부러 중복된 데이터를 저장하여 조인 없이 빠른 조회 성능을 얻는 방식.

결론적으로, 정규화는 중복을 피하고 여러 테이블을 생성하여 필요한 데이터를 조인을 통해 조회하는 방식이고, 역정규화는 일부러 데이터를 중복 저장하여 조회 성능을 최적화하는 방식입니다.

    @Override
    @Transactional
    public Object downloadTransactionTallowEvidence(Member member, long id) {
        // 중복 확인
        int check = transactionRepository.checkTallowEvidence(id);

        String fileName;
        String originFileName;

        if(check == 0) {
            // transaction title 조회
            String title = transactionRepository.getTransactionTitle(id);

            // 특수 문자를 언더스코어로 대체
            originFileName = title.replaceAll("[\\\\/:*?\"<>|]", "");

            // 공백을 언더스코어로 대체
            originFileName = originFileName.replaceAll("\\s", "_");
            originFileName += "_tallow.zip";

            fileName = UUID.randomUUID().toString() + ".zip";

            // tallow_transaction_id로 tallow 목록 가져오기
            List<TallowDto.GetTallow> list = transactionRepository.getTransactionTallows(id);

            // zip 파일 생성
            ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();

            try (ZipOutputStream out = new ZipOutputStream(zipOutputStream)) {
                for(TallowDto.GetTallow tallow : list) {
                    S3Object s3Object = amazonS3.getObject(new GetObjectRequest(bucket, tallow.getTallowEvidence()));
                    S3ObjectInputStream objectInputStream = s3Object.getObjectContent();

                    byte[] objectBytes = IOUtils.toByteArray(objectInputStream);

                    // 각 객체를 zip에 추가
                    ZipEntry zipEntry = new ZipEntry(tallow.getTallowEvidence());
                    out.putNextEntry(zipEntry);
                    out.write(objectBytes);
                    out.closeEntry();
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }

            byte[] zipBytes = zipOutputStream.toByteArray();

            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(zipBytes);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(zipBytes.length);

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, fileName, byteArrayInputStream, metadata);
            putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);

            // zip 파일 s3 upload
            PutObjectResult awsResult = amazonS3.putObject(putObjectRequest);

            TallowTransactionFilesDto.PostTallowTransactionFiles file = TallowTransactionFilesDto.PostTallowTransactionFiles.builder()
                    .tallowTransactionId(id)
                    .fileName(fileName)
                    .originFileName(originFileName)
                    .type("TALLOW")
                    .fileType("ZIP")
                    .build();

            int dbResult = transactionRepository.insertTransactionFile(file);
        }
        else {
            TallowTransactionFilesDto.GetTallowTransactionFiles file = transactionRepository.getTallowTransactionFiles(id);

            fileName = file.getFileName();
            originFileName = file.getOriginFileName();
        }

        // aws pre-signed url 생성
        GeneratePresignedUrlRequest generatePresignedUrlRequest = getGeneratePreSignedUrlRequest(bucket, fileName, originFileName);
        URL url = amazonS3.generatePresignedUrl(generatePresignedUrlRequest);

        // pre-signed url 메일 전송
        try {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
            helper.setFrom("support@recycleledger.com");
            helper.setSubject("File download information");
            helper.setTo(member.getEmail());

            Context context = new Context();
            context.setVariable("downloadUrl", url);

            helper.setText(templateEngine.process("mail/file-download", context), true);

            javaMailSender.send(message);
        }
        catch (MessagingException e) {
            e.printStackTrace();
        }

        return null;
    }

 

  @Override
    @Transactional
    public URL downloadTransactionTallowEvidence(Member member, long id) {
        // 중복 확인
        int check = transactionRepository.checkTallowEvidence(id);

        String fileName;
        String originFileName;

        if(check == 0) {
            // transaction title 조회
            String title = transactionRepository.getTransactionTitle(id);

            // 특수 문자를 언더스코어로 대체
            originFileName = title.replaceAll("[\\\\/:*?\"<>|]", "");

            // 공백을 언더스코어로 대체
            originFileName = originFileName.replaceAll("\\s", "_");
            originFileName += "_tallow.zip";

            fileName = UUID.randomUUID().toString() + ".zip";

            // tallow_transaction_id로 tallow 목록 가져오기
            List<TallowDto.GetTallow> list = transactionRepository.getTransactionTallows(id);

            // zip 파일 생성
            ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();

            try (ZipOutputStream out = new ZipOutputStream(zipOutputStream)) {
                for(TallowDto.GetTallow tallow : list) {
                    S3Object s3Object = amazonS3.getObject(new GetObjectRequest(bucket, tallow.getTallowEvidence()));
                    S3ObjectInputStream objectInputStream = s3Object.getObjectContent();

                    byte[] objectBytes = IOUtils.toByteArray(objectInputStream);

                    // 각 객체를 zip에 추가
                    ZipEntry zipEntry = new ZipEntry(tallow.getTallowEvidence());
                    out.putNextEntry(zipEntry);
                    out.write(objectBytes);
                    out.closeEntry();
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }

            byte[] zipBytes = zipOutputStream.toByteArray();

            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(zipBytes);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(zipBytes.length);

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, fileName, byteArrayInputStream, metadata);
            putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);

            // zip 파일 s3 upload
            PutObjectResult awsResult = amazonS3.putObject(putObjectRequest);

            TallowTransactionFilesDto.PostTallowTransactionFiles file = TallowTransactionFilesDto.PostTallowTransactionFiles.builder()
                    .tallowTransactionId(id)
                    .fileName(fileName)
                    .originFileName(originFileName)
                    .type("TALLOW")
                    .fileType("ZIP")
                    .build();

            int dbResult = transactionRepository.insertTransactionFile(file);
        }
        else {
            TallowTransactionFilesDto.GetTallowTransactionFiles file = transactionRepository.getTallowTransactionFiles(id);

            fileName = file.getFileName();
            originFileName = file.getOriginFileName();
        }

        // aws pre-signed url 생성
        GeneratePresignedUrlRequest generatePresignedUrlRequest = getGeneratePreSignedUrlRequest(bucket, fileName, originFileName);
        URL url = amazonS3.generatePresignedUrl(generatePresignedUrlRequest);

        // pre-signed url 메일 전송
//        try {
//            MimeMessage message = javaMailSender.createMimeMessage();
//            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
//            helper.setFrom("support@recycleledger.com");
//            helper.setSubject("File download information");
//            helper.setTo(member.getEmail());
//
//            Context context = new Context();
//            context.setVariable("downloadUrl", url);
//
//            helper.setText(templateEngine.process("mail/file-download", context), true);
//
//            javaMailSender.send(message);
//        }
//        catch (MessagingException e) {
//            e.printStackTrace();
//        }

        return url;
    }

 

+ Recent posts