oracle cloud instance 살리기

잘 동작하던 오라클 클라우드 인스턴스가 어느날 갑자기 부팅되지 않아서 상당히 난감했었는데, 아래 방법을 통해서 살릴 수 있었다.

Instances -> [dead instance] -> Boot volume -> [dead boot volume] -> Boot Volume Backups -> Create Boot Volume Backup

create new instance and new boot volume

Instances -> [new instance] -> Attached block volumes -> Attach block volume -> Select volume -> select [backup boot volume]

새로운 instance 의 shell 로 접속해서 sudo fdisk -l 하면 /dev/sdb1에 backup boot volume이 보임

mkdir /media/olddisk
sudo mount /dev/sdb1 /media/olddisk

/media/olddisk로 접속해서 데이터 살리기

sudo umount /media/olddisk

Instances -> [new instance] -> Attached block volumes -> detatch [backup boot volume]

참고. mysql 살리기

cp /media/olddisk/usr/sbin/mysqld /usr/sbin/
cp /media/olddisk/usr/bin/mysql* /usr/bin/
cp -r /media/olddisk/var/lib/mysql /var/lib/
cp -r mysql-files /var/lib/
cp -r mysql-keyring /var/lib/
cp -r mysql-upgrade /var/lib/
sudo apt install mysql-server

Spring boot JPA

source code 는 아래 github 에서 받을 수 있습니다.
https://github.com/nanbean/springReact 의 spring-jpa branch해당 source code 받지 말고 아래대로 차근 차근 scratch 부터 만들어 보는 것을 추천합니다.

# 해당 source code 를 통해서 동작성을 빠르게 확인하려면,
$ git clone -b spring-jpa https://github.com/nanbean/springReact.git lcms
$ cd lcms
$ mvn spring-boot:run

이후 REST API 동작성 확인 으로 이동하시면 됩니다.

이전 spriing react 최신 기준으로 시작합니다.(Spring boot React)

spring-boot-devtools, h2, JPA, hsqldb, lombok 을 Dependency 에 추가

1. 이전 project 에서 pom.xml 의 dependency 에 spring-boot-devtools, h2, jpa, hsqldb, lombok 을 추가한다. dependencies 하위에 추가합니다.

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>


		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

Content.java 추가

1. src/main/java/com/lge/lcms/content 디렉토리를 만들고 Content.java 파일을 하위에 생성합니다.

title 과 genre 만 가진 간단한 Entity 입니다.

package com.lge.lcms.content;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Column;

@NoArgsConstructor
@Table
@Getter
@Entity
public class Content {

	@Id
	@GeneratedValue
	private Long id;

	@Column
	private String title;

	@Column
	private String genre;

	@Builder
	public Content(String title, String genre) {
		this.title = title;
		this.genre = genre;
	}
}

ContentRepository.java 파일 추가

1. src/main/java/com/lge/lcms/content  하위에 ContentRepository.java 파일을 추가합니다.

package com.lge.lcms.content;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ContentRepository extends JpaRepository<Content, Long> {

}

ContentRepositoryTest.java 파일 추가

1. src/test/java/com/lge/lcms/content  하위에 ContentRepository.java 파일을 추가합니다.

package com.lge.lcms.content;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Test;
import org.junit.After;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ContentRepositoryTest {

		@Autowired
		ContentRepository contentRepository;

		@After
		public void cleanup() {
			contentRepository.deleteAll();
		}

		@Test
		public void getTest() {
			contentRepository.save(Content.builder()
				.title("Incredible")
				.genre("Action")
				.build());

			List<Content> contentList = contentRepository.findAll();

			Content content = contentList.get(0);
			assertThat(content.getTitle(), is("Incredible"));
			assertThat(content.getGenre(), is("Action"));
		}
}

Test 실행

1. Test 를 통해서 Build 가 정상적으로 되는지 Test Result 가 정상인지 확인 합니다.

$ mvn test
...
...
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 29.654 s
[INFO] Finished at: 2019-01-30T13:36:29+09:00
[INFO] Final Memory: 42M/576M
[INFO] ------------------------------------------------------------------------

Rest API 추가

1. src/main/java/com/lge/lcms/web 디렉토리를 만들고 ContentRestController.java 파일을 하위에 생성합니다.

rest/content REST API 를 만듭니다.

package com.lge.lcms.web;

import com.lge.lcms.dto.ContentSaveRequestDto;
import com.lge.lcms.content.ContentRepository;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@AllArgsConstructor
@RequestMapping("/rest")
public class ContentRestController {

	private ContentRepository contentRepository;

	@PostMapping("/content")
	public void savePosts(@RequestBody ContentSaveRequestDto dto){
		contentRepository.save(dto.toEntity());
	}
}

DTO 추가

1. src/main/java/com/lge/lcms/dto 디렉토리를 만들고 ContentSaveRequestDto.java 파일을 하위에 생성합니다.

View 를 생성합니다. View 와 Entity 는 구분하는 것이 좋습니다.

package com.lge.lcms.dto;

import com.lge.lcms.content.Content;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.Getter;

@Getter
@Setter
@NoArgsConstructor
public class ContentSaveRequestDto {

		private String title;
		private String genre;

		public Content toEntity(){
			return Content.builder()
				.title(title)
				.genre(genre)
				.build();
		}
}

REST API 동작성 확인

1. H2 활성화, src/main/resources/application.properties 에 아래 내용을 추가합니다.

H2 DB 를 웹브라우저를 통해서 접근하기 위해서입니다.

spring:
	h2:
		console:
			enabled: true

2. spring boot 실행

$ mvn spring-boot:run

3. post 수행

$ curl --header "Content-Type: application/json" --request POST --data '{"title": "Incredible","genre": "Action"}' http://localhost:8080/rest/content

4. 입베디드 H2 consle 진입

브라우저 주소창에 http://localhost:8080/h2-console 을 입력합니다.

5. connect

JDBc URL 에 jdbc:h2:mem:testdb 을 입력하고 connect 를 눌러서 진입합니다.

7. query 를 통해서 POST API 동작 확인합니다.

아래 query 를 입력하고 Run 버튼을 누릅니다.

SELECT * FROM CONTENT; 

Spring boot React

source code 는 아래 github 에서 받을 수 있습니다.
https://github.com/nanbean/springReact
해당 source code 받지 말고 아래대로 차근 차근 scratch 부터 만들어 보는 것을 추천합니다.

# 해당 source code 를 통해서 동작성을 빠르게 확인하려면,
$ git clone https://github.com/nanbean/springReact.git lcms
$ cd lcms
$ mvn clean install
$ java -jar target/lcms-0.0.1-SNAPSHOT.jar
후
browser 에서 http://localhost:8080/ 접속하면 됩니다.

Bootstrap 제작

spring 에서 제공하는 기본을 이용해서 skeleton code 를 만드는 과정입니다.

1. https://start.spring.io 에서 Gropu 에 com.lge, Artifact 에 lcms 입력, Web Dependencies 추가해서 Generate Project

2. 다운 받은 파일을 특정 폴더(spring-react)에 압축 풀기

tree 구조는 아래와 같습니다.

jeongsim.kim@ubuntu-n:~/work/lcms$ tree
.
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── lge
    │   │           └── lcms
    │   │               └── LcmsApplication.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── lge
                    └── lcms
                        └── LcmsApplicationTests.java

14 directories, 6 files

기본 Controller 추가

Rest API 를 추가하는 작업입니다. (/api/hello)

1. src/main/java/com/lge/lcms/HelloController.java 파일 생성

package com.lge.lcms;
 
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.Date;
 
@RestController
public class HelloController {
    @GetMapping("/api/hello")
    public String hello() {
        return "Hello, the time at the server is now " + new Date() + "\n";
    }
}

2. 실행

$ mvn spring-boot:run

3. 아래 curl 로 정상 동작 여부 확인 (다른 터미널에서)

$ curl http://localhost:8080/api/hello
Hello, the time at the server is now Tue Jan 29 14:41:10 KST 2019

React 추가

Front-end 로 React 를 사용하기 위해서 facebook 에서 만든 create-react-app 을 이용해서 React bootstrap 을 만드는 과정입니다.

1. 최상위 디렉토리에서 아래와 같이 frontend React Application 추가 (mvn spring-boot:run 종료하고)

$ create-react-app frontend

create-react-app 이 설치되어 있지 않다면?

$ npm install -g create-react-app

React 에 API 연결 추가

Front-end 인 React App 에서 spring 으로 Rest API 를 호출하여, 페이지에 그려주는 코드를 작성하는 것입니다.

1. frontend/src/App.js 파일을 아래와 같이 수정

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
 
class App extends Component {
    state = {};
 
    componentDidMount() {
        setInterval(this.hello, 250);
    }
 
    hello = () => {
        fetch('/api/hello')
            .then(response => response.text())
            .then(message => {
                this.setState({message: message});
            });
    }
 
    render() {
        return (
            <div className="App">
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    <h1 className="App-title">{this.state.message}</h1>
                    <p>
                        Edit <code>src/App.js</code> and save to reload.
                    </p>
                    <a
                        className="App-link"
                        href="https://reactjs.org"
                        target="_blank"
                        rel="noopener noreferrer"
                    >
                        Learn React
                    </a>
                </header>
            </div>
        );
    }
}
 
export default App;

Maven 으로 React Packaging 추가

maven 을 통해서 Front-end 인 React 를 build 하는 것입니다.

1. pom.xml 파일에 아래와 같이 plugin 추가(build/plugins 하위에 추가하면 됩니다.)

		<plugin>
			<groupId>com.github.eirslett</groupId>
			<artifactId>frontend-maven-plugin</artifactId>
			<version>1.6</version>
			<configuration>
				<workingDirectory>frontend</workingDirectory>
				<installDirectory>target</installDirectory>
			</configuration>
			<executions>
				<execution>
					<id>install node and npm</id>
					<goals>
						<goal>install-node-and-npm</goal>
					</goals>
					<configuration>
						<nodeVersion>v8.9.4</nodeVersion>
						<npmVersion>5.6.0</npmVersion>
					</configuration>
				</execution>
				<execution>
					<id>npm install</id>
					<goals>
						<goal>npm</goal>
					</goals>
					<configuration>
						<arguments>install</arguments>
					</configuration>
				</execution>
				<execution>
					<id>npm run build</id>
					<goals>
						<goal>npm</goal>
					</goals>
					<configuration>
						<arguments>run build</arguments>
					</configuration>
				</execution>
			</executions>
		</plugin>

2. mvn clean install 이 정상적으로 되는지 확인 (Error 가 뜨는지 안 뜨는지?)

$ mvn clean install

3. tree 구조 확인

frontend 하위에 build 가 정상적으로 생성되는지?(maven 이 npm 을 호출해서 build 를 잘 했는지 확인)

$ tree frontend/build
frontend/build
├── asset-manifest.json
├── favicon.ico
├── index.html
├── manifest.json
├── precache-manifest.18b2b7a023755c5bb0bcd527b6c170b9.js
├── service-worker.js
└── static
    ├── css
    │   ├── main.24e815be.chunk.css
    │   └── main.24e815be.chunk.css.map
    ├── js
    │   ├── 1.fa92c112.chunk.js
    │   ├── 1.fa92c112.chunk.js.map
    │   ├── main.21cc7467.chunk.js
    │   ├── main.21cc7467.chunk.js.map
    │   ├── runtime~main.229c360f.js
    │   └── runtime~main.229c360f.js.map
    └── media
        └── logo.5d5d9eef.svg

4 directories, 15 files

Spring boot jar 에 React 추가

maven 을 통해서 만들어진 Front-end 리소스들을 jar 에 추가하는 작업입니다.

1. pom.xml 에 plugin 추가

			<plugin>
				<artifactId>maven-antrun-plugin</artifactId>
				<executions>
					<execution>
						<phase>generate-resources</phase>
						<configuration>
							<target>
								<copy todir="${project.build.directory}/classes/public">
									<fileset dir="${project.basedir}/frontend/build"/>
								</copy>
							</target>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

2. mvn clean install 이 정상적으로 되는지 확인 (Error 가 뜨는지 안 뜨는지?)

$ mvn clean install

3. jar 파일에 public resource 가 정상적으로 포함되어 있는지 확인

$ jar tvf target/lcms-0.0.1-SNAPSHOT.jar | grep public
     0 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/
     0 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/
     0 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/media/
     0 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/css/
     0 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/js/
   306 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/manifest.json
322072 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/js/1.fa92c112.chunk.js.map
  1041 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/service-worker.js
  7959 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/js/main.21cc7467.chunk.js.map
  2828 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/css/main.24e815be.chunk.css.map
  1502 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/js/runtime~main.229c360f.js
  1706 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/js/main.21cc7467.chunk.js
   606 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/precache-manifest.18b2b7a023755c5bb0bcd527b6c170b9.js
   779 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/asset-manifest.json
  2062 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/index.html
  2671 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/media/logo.5d5d9eef.svg
  3870 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/favicon.ico
   984 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/css/main.24e815be.chunk.css
  7996 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/js/runtime~main.229c360f.js.map
112436 Tue Jan 29 15:00:30 KST 2019 BOOT-INF/classes/public/static/js/1.fa92c112.chunk.js

실행 확인

Front-end 와 Back-end 가 정상적으로 동작하는지 확인하는 것입니다.

1. java 로 실행 확인

$ java -jar target/lcms-0.0.1-SNAPSHOT.jar 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)
...

2. browser 에서 정상 동작 확인

Zsh, Oh My ZSH 사용하기

zsh 설치

$ sudo apt install zsh

oh my zsh 설치

// curl 을 통해 설치
$ sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
// wget 을 통해 설치
$ sh -c "$(wget https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh -O -)"
// 둘 중 하나를 고르면 되고, 해당 내용은 https://ohmyz.sh/ 에 가이드가 있음

Oh My ZSH Theme 변경

$ vi ~/.zshrc
// ZSH_THEME 부분을 변경
ZSH_THEME="agnoster"