aws 서버에 프로젝트 배포를 하는데 build fail 오류가 생겨 해결방법을 기록한다git으로 서버배포할 때 참고한 블로그

-> https://velog.io/@wndudrla1011/chapter-8

 

EC2 서버에 프로젝트 배포하기 - 루타블의 개발일기

🔧 먼저 깃허브에서 코드를 받아올 수 있게 EC2에 깃을 설치하겠다.sudo yum install git🔧 설치가 완료되면 다음 명령어로 설치 상태를 확인git --version🔧 git이 성공적으로 설치되면 git clone으로 프로

velog.io

위에 스텝대로 무난히 진행되다가 build fail 메세지가 출력됨 

$ ./deploy.sh
> Git Pull
Already up to date.
> 프로젝트 Build 시작
Starting a Gradle Daemon (subsequent builds will be faster)

FAILURE: Build failed with an exception.

* What went wrong:
Directory '/home/ubuntu/app/repository/MyApp' does not contain a Gradle build.

A Gradle build should contain a 'settings.gradle' or 'settings.gradle.kts' file in its root directory. It may also contain                                                     a 'build.gradle' or 'build.gradle.kts' file.

To create a new Gradle build in this directory run 'gradlew init'

For more information about the 'init' task, please refer to https://docs.gradle.org/8.5/userguide/build_init_plugin.html i                                                    n the Gradle documentation.

For more details on creating a Gradle build, please refer to https://docs.gradle.org/8.5/userguide/tutorial_using_tasks.ht                                                    ml in the Gradle documentation.

* Try:
> Run gradlew init to create a new Gradle build in this directory.
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Get more help at https://help.gradle.org.

천천히 읽어보니 setting.gradle이 없단다..

로컬에서 프로젝트 폴더에 확인해보니 정말 없다..어휴 결국 직접 파일을 만들어 git에 push 해주었다

#settings.gradle
rootProject.name = 'MyApp'

settinds.gradle 파일은 build.gradle과 같은 경로에 생성해주었다.

다시 ec2로 가서 빌드설정파일을 실행해주었다

$ ./deploy.sh
> Git Pull
remote: Enumerating objects: 32, done.
remote: Counting objects: 100% (32/32), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 17 (delta 6), reused 17 (delta 6), pack-reused 0
Unpacking objects: 100% (17/17), 7.59 KiB | 22.00 KiB/s, done.
From https://github.com/ds-jeong/MyApp
   5fce017..21f8cda  master     -> origin/master
Updating 5fce017..21f8cda
Fast-forward
 .gradle/8.5/executionHistory/executionHistory.bin  | Bin 440109 -> 440109 bytes
 .gradle/8.5/executionHistory/executionHistory.lock | Bin 17 -> 17 bytes
 .gradle/8.5/fileHashes/fileHashes.bin              | Bin 41647 -> 41647 bytes
 .gradle/8.5/fileHashes/fileHashes.lock             | Bin 17 -> 17 bytes
 .gradle/buildOutputCleanup/buildOutputCleanup.lock | Bin 17 -> 17 bytes
 .gradle/file-system.probe                          | Bin 8 -> 8 bytes
 build/libs/MyApp-0.0.1-SNAPSHOT-plain.jar          | Bin 6494917 -> 6494917 bytes
 settings.gradle                                    |   1 +
 8 files changed, 1 insertion(+)
 create mode 100644 settings.gradle
> 프로젝트 Build 시작
<-<-------------> 0% CONFIGURING [11m 13s]
> root project
^C^Z
[1]+  Stopped                 ./deploy.sh

오? 된거같다 근데 command가 멈췃다

흠..springBoot 프로젝트를 배포할땐 느리다는데 그문제인가..

서치를 해보니 나같은 경우가 있더라 

->https://sundries-in-myidea.tistory.com/102

 

AWS EC2 프리티어에서 메모리 부족현상 해결방법

AWS free tier를 사용하다보면 2%가 부족할 때가 있다. AWS 프리티어는 가난한 대학생에게는 한줄기 빛과 같은 존재인데, AWS의 프리티어라서 적게 돈이 나가는 것도 좋고, 실제로 이것저것 해볼 수 있

sundries-in-myidea.tistory.com

감사하게도 위 블로그를 참고했더니 1분도안되서 빌드가 끝나고 튕기는 현상도 없다

$ ./deploy.sh
> Git Pull
Already up to date.
> 프로젝트 Build 시작
Starting a Gradle Daemon, 1 busy Daemon could not be reused, use --status for details

> Task :buildEnvironment

------------------------------------------------------------
Root project 'MyApp'
------------------------------------------------------------

classpath
No dependencies

A web-based, searchable dependency report is available by adding the --scan option.

BUILD SUCCESSFUL in 12s
1 actionable task: 1 executed
> step1 디렉토리로 이동
> Build 파일 복사
> 현재 구동 중인 애플리케이션 pid 확인
현재 구동 중인 애플리케이션 pid:
> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않는다.
> 새 애플리케이션 배포
> JAR Name: MyApp-0.0.1-SNAPSHOT-plain.jar

제대로 올라간듯 하다

-> https://velog.io/@m1njae/AWS-%ED%83%84%EB%A0%A5%EC%A0%81-IP-%EC%A3%BC%EC%86%8C-%EC%84%A4%EC%A0%95

 

[AWS] 탄력적 IP 주소 설정

EC2 인스턴스를 껐다가 다시 실행하면 IP가 변경된다고? 탄력적 IP 주소를 설정하자!

velog.io

위에 블로그를 참고해서 화면을 위한 탄력 ip를 할당받았다

-> https://velog.io/@hoooons/AWS-EC2-%EB%A1%9C-React-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0

그리곤 위에 블로그를 참고해서 여러 패키지를 다운로드를 완료했다 

npm error code ENOSPC
npm error syscall write
npm error errno -28
npm error nospc ENOSPC: no space left on device, write
npm error nospc There appears to be insufficient space on your system to finish.
npm error nospc Clear up some disk space and try again.
npm error A complete log of this run can be found in: /home/ubuntu/.npm/_logs/2024-08-05T13_08_44_437Z-debug-0.log

react root 폴더에서 npm start 명령어를 시도했더니 위와 같은 에러를 뱉는다..

서버에서 최적화하고 난리를 쳐도 안되길래 서치끝에 찾아냈다

pakage.json내에 sourcemap 를 false 처리해주는것..

보통 개발환경에서는 바로 소스코드를 확인할수 있도록 디폴트가 true로 되있지만

실서버에선 소스코드를 확인할 일이 없고, 빌드시 해당 과정에서 메모리를 많이 사용한다..

#pakage.json
  /*    "build": "react-scripts build",*/
  "scripts": {
    "start": "react-scripts start",
    "build" : "GENERATE_SOURCEMAP=false react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

해서 위와 같이 수정 후 git에 반영해주고 aws에서는 다시 pull.. 

수정 된 json 파일을 가지고 왔지만 혹시 몰라 디스크공간을 확보 위까지 진행했다

/*시스템 재부팅*/
$ sudo reboot

여기까지하고 보통 npm start가 된다

주소창에 탄력ip:3000으로 치면 화면이나와야 정상

혹시 몰라 aws에 보안 그룹을 확인해보니 3000 port 는 열려있음

원인을 찾다가 캐시문제인가 싶어서 아래 스텝을 진행해보았다

/*임시 파일 삭제*/
$ sudo rm -rf /tmp/*

/*로그 파일 삭제*/
$ sudo rm -rf /var/log/*.log

/*npm 캐시 삭제*/
npm cache clean --force

/*패키지 제거*/
$ sudo apt-get autoremove
$ sudo apt-get clean

/*시스템 재부팅*/
$ sudo reboot

여기까지 실행 후 npm 재설치를 해줬는데.. 여전한 에러..

$ npm install
npm error code ENOTEMPTY
npm error syscall rename
npm error path /home/ubuntu/app/repository/MyApp/src/main/frontend/node_modules/acorn
npm error dest /home/ubuntu/app/repository/MyApp/src/main/frontend/node_modules/.acorn-I5v5oviz
npm error errno -39
npm error ENOTEMPTY: directory not empty, rename '/home/ubuntu/app/repository/MyApp/src/main/frontend/node_modules/acorn' -> '/home/ubuntu/app/repository/MyApp/src/main/frontend/node_modules/.acorn-I5v5oviz'
npm error A complete log of this run can be found in: /home/ubuntu/.npm/_logs/2024-08-05T13_25_20_689Z-debug-0.log
/*node_modules 삭제*/
$ rm -rf node_modules

/*npm 캐시 clean*/
$ npm cache clean --force
$ npm install

/*package-lock.json 삭제*/
$ rm package-lock.json
$ npm install

/*node_modules 권한 수정*/
$ sudo chown -R $USER:$GROUP node_modules

/*.npm 디렉토리 권한 및 파일 확인*/
sudo chown -R $USER:$GROUP ~/.npm

/*시스템 재부팅*/
$ sudo reboot

이제서야 된다..흠? node_modules 충돌인건가; 어쨋든 서버가 올라가는걸 확인했다

쇼핑몰 프로젝트를 진행중인데 목록에 이미지가 노출되야하는데 계속 경로를 못찾아왔다
프로젝트 폴더 경로가 D:에 있으니 파일에 액세스를 못하더라
그래서 일단 프로젝트 경로부터 C:로 옮겼다 그런데 계속 빌드가 안되는 일이발생..
gradle로 빌드를 하려는데 build.gradle을 찾을수가 없으니 폴더를 생성하라는 메세지가 나와서 git에있던 파일을 가져오니 정상적으로 프로젝트가 동작했다
여기까진 그렇다치고..경로를 어디로 해야 React에서 찾을수 있나보니 public으로 보통 경로를 찾아간다 하더라
그래서 public 밑에 upload 폴더를 만들어서 업로드해보니 파일이 생성되었다 생성된 경로로 크롬 주소로 찍어보니 이미지가나오길래 해당 경로를 그대로 img 태그로 가져왔다

<tbody>
{resArr.map((item, index) => (
    <tr key={index}>
        <td>
            <img
            	//process.env.PUBLIC_URL은 public 디렉토리다
                src={process.env.PUBLIC_URL + '/upload/img/' + item.fileNm}
                alt="productImg"
                style={{height: "4.3rem"}}
            />
        </td>
        <td>{item.productNm}</td>
        <td>{item.price}</td>
        <td>{item.author}</td>
    </tr>
))}
</tbody>

  

프로젝트의 폴더구조이다 참고하도록하자

 

'React' 카테고리의 다른 글

React / useHistory가 import 안될때  (0) 2024.07.11
import { useHistory } from 'react-router-dom';

axios 통신 후 화면 목록으로 이동하기 위해 useHistory 사용했더니 import가 안됨
아래코드로 수정 후 반영했더니 화면이동 가능..

import { useNavigate } from 'react-router-dom';
import React, { useState, useRef } from 'react';
import { Form, Button, Container } from 'react-bootstrap';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';

function Write() {
    //폼전송
    const titleRef = useRef();
    const contentRef = useRef();
    const nicknameRef = useRef();
    const fileRef = useRef();
    const navigate = useNavigate();

    const handleSubmit = event => {

        event.preventDefault();

        const formData = new FormData();
        formData.append('title', titleRef.current.value);
        formData.append('content', contentRef.current.value);
        formData.append('nickname', nicknameRef.current.value);
        formData.append('file', fileRef.current.files[0]); // 첨부된 이미지 파일 추가


        axios.post('/qna/qnaSave', formData)
            .then(response => {
                // console.log('Post submitted successfully');
                alert("작성완료되었습니다.");
                // useHistory import 안되면 아래 코드로 수정해서 반영
                // 응답을 받고 Qna화면으로 돌아감
                navigate('/qna');
            })
            .catch(error => {
                console.error('Error submitting post: ', error);
            });
    };

    //파일업로드
    const [selectedFile, setSelectedFile] = useState(null);

    const fileSelectedHandler = event => {
        setSelectedFile(event.target.files[0]);
        //console.log(event.target.files[0]);
    };

    const fileUploadHandler = () => {
        const formData = new FormData();
        formData.append('file', selectedFile);

        axios.post('/utill/imgUpload', formData)
            .then(response => {
                //console.log(response.data);
                // Handle success, e.g., show a success message
            })
            .catch(error => {
                console.error('Error uploading file: ', error);
                // Handle error, e.g., show an error message
            });
    };

    return (
        <div>
            <Container>
                <Form onSubmit={handleSubmit}>
                    <Form.Group controlId="formTitle">
                        <Form.Label>제목</Form.Label>
                        <Form.Control type="text" ref={titleRef} />
                    </Form.Group>

                    <Form.Group controlId="formContent">
                        <Form.Label>내용</Form.Label>
                        <Form.Control as="textarea" rows={5} ref={contentRef} />
                    </Form.Group>

                    <Form.Group controlId="formNickname">
                        <Form.Label>닉네임</Form.Label>
                        <Form.Control type="text" ref={nicknameRef} />
                    </Form.Group>

                    <Form.Group controlId="formImage">
                        <Form.Label>이미지 첨부</Form.Label>
                        <Form.Control type="file" ref={fileRef} onChange={fileSelectedHandler} />
                    </Form.Group>

                    <Button variant="primary" type="submit">
                        작성 완료
                    </Button>
                </Form>
            </Container>
             {/*<button onClick={fileUploadHandler}>Upload</button>*/}
        </div>
    );
}

export default Write;



'React' 카테고리의 다른 글

React / 이미지 경로  (0) 2024.07.11

기존에 쓰던 postgresql과 달리 oracle은 사용법이 달라 기록한다

1.Postgresql

SELECT * FROM TEST_TABLE A 
WHERE A.COLUMN LIKE CONCAT( '%' , #{param.column} , '%')

2.Oracle

SELECT * FROM TEST_TABLE A WHERE A.COLUMN LIKE '%'||#{param.column}||'%'

 

JPA란 Java Persistance API의 약자로서 자바 ORM(Object Relational Mapping) 기술에 대한

표준명세(구조와 기능을 상세하게 기술한 문서)로  JAVA에서 제공하는 API이다

JPA의 스펙은 자바객체와 데이터베이스를 어떻게 매핑하고 동작해야하는지를 정의한다

 

RAM에 있는 데이터들은 휘발성데이터이다

컴퓨터를 부팅하면 열려있던 창이 종료되있는데 이런것들을 휘발성데이터라고 생각하면된다

하드디스크는 비휘발성데이터로 영속성의 특징을 가지고있다

영속성의 특징이란 지속적인 데이터란 뜻으로 데이터가 유지되는 것을 의미한다

JPA(Java Persistance API)는 자바가 지원하는 표준명세로서 ORM을 이용해 DataBase를 매핑할때

하드디스크에 DataBase 영역을 만들어 그안에 데이터를 저장하게 되는데

이러한 데이터들을 영속성(Persistance)데이터라 한다

JPA 는 자바객체가 영속성데이터를 가질 수 있게하는 인터페이스라고 이해하면 편리하다

 

 


 

JPA 에 관한 설명을 이해하는 중 ORM이라는 개념을 이해하기 위해 정리해보겠다

ORM은 객체-관계 매핑을 의미하는데 SQL Mapper와 비교되고 있다

 

SQL Mapper

  • sql문을 직접 기술하여 데이터베이스를 조작한다
  • 필드를 매핑하여 데이터베이스에 접근한다

 

 ORM(Obejct Relational Mapping / 객체-관계 매핑)

  • 메서드로 데이터베이스를 조작한다
  • sql문을 자동으로 생성한다

 


 

Spring-Data-JPA

만약, 개발자가 JPA 구현체를 호출하여 Java와 DataBase가 ConnectionPool(연결) 할 수있는 코드를 작성한다면

DB연결이 필요할때 마다 동일한 코드들을 작성해야하는 반복되는 과정이 생길 것이다

Spring은 반복되는 코드들을 interface로 제공해주어 편리하게 사용이 가능하도록 제공해주는데

이것을 Spring-Data-JPA 모듈이라고 한다

 

https://suhwan.dev/2019/02/24/jpa-vs-hibernate-vs-spring-data-jpa/ 참고

 

JPA, Hibernate, 그리고 Spring Data JPA의 차이점

개요 Spring 프레임워크는 어플리케이션을 개발할 때 필요한 수많은 강력하고 편리한 기능을 제공해준다. 하지만 많은 기술이 존재하는 만큼 Spring 프레임워크를 처음 사용하는 사람이 Spring 프레

suhwan.dev

 

'Spring' 카테고리의 다른 글

Spring / request.getHeader()  (0) 2022.07.15
Spring / Security  (0) 2022.07.15
Spring / Spring Boot 에 Intercapter 란?  (0) 2022.07.14
Spring / Thymeleaf  (0) 2022.07.14

intelij에서 서버를 로드했을때 나오는 에러이다

1099포트가 사용중이라는 것 같은데

cmd 창을 실행 후

netstat -ano|find "1099"

현재 실행 중인 프로그램들이 뜬다

 

끝에보이는 9376 pid를 가진 프로그램들을 삭제하기위해

작업관리자 - 세부정보에서 pid가 9376인 프로그램들을 종료한다

그리고 서버를 가동하면 정상적으로 로드됨

driverClassName를 인식하지 못해서 생기는 문제이다

root-context.xml

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
        <property name="url" value="jdbc:log4jdbc:postgresql://ip:port/db명"></property>
        <property name="username" value="db접속아이디"></property>
        <property name="password" value="db접속비번"></property>
</bean>

 

log4jdbclog4jdbc.log4j2.properties

log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.slf4jSpyLogDelegat

 

클래스명(slf4jSpyLogDelegat)의 s가 소문자로 되있었는데 클래스명은 Slf4jSpyLogDelegat이다

대문자로 고쳐주었더니 정상적으로 로드되었다

수정 전

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "//mybatis.org/DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jds.mavenSpringProject.mapper.UserMapper">
    <select id="getUserList" parameterType="UserVO" resultType="UserVO"><![CDATA[
        SELECT USER_NM
        FROM CMPNY_USER
    ]]></select>
</mapper>

 

수정 후

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "//mybatis.org/DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jds.mavenSpringProject.mapper.UserMapper">
    <select id="getUserList" parameterType="com.jds.mavenSpringProject.vo.UserVO" resultType="com.jds.mavenSpringProject.vo.UserVO"><![CDATA[
        SELECT USER_NM
        FROM CMPNY_USER
    ]]></select>
</mapper>

 

parameterType의 경로를 찾을 수 없어 생긴 오류였다

+ Recent posts