노션에서 벨로그로 옮긴 내용들이다!
원문 : docker study
프로젝트를 컨테이너에 올리는 방식을 공부하고 적용하고 싶어서 docker를 이용해 공부를 해보았다.
OS는 Mac m1을 사용하였다.
나는 m1칩이여서 Mac with Apple chip 클릭
끌어다 놓으면 설치 완료
여기서 쉽게 실행되고 있는 container 리스트나 image들을 확인할 수 있다.
나는 이미 계정이 있기에 프로젝트 터미널에서
docker login이라는 명령어를 실행하여 로그인을 하면 자동으로 로그인이 되었다.
계정이 없다면 아래 링크를 통해서 가입해주기 >.0
가입해주고 repository도 생성을 해주어야한다.
Docker Hub Container Image Library | App Containerization
spring boot 로 docker를 실행해줄거니까 spring boot 프로젝트를 만든다.
우선 Application의 전체 파일 구성, 필요한 구성은 아래와 같다.
1) maven 설정
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gmc</groupId>
<artifactId>docker-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>docker-test</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
위와 같이 의존성을 추가해줍니다.
원래 기존에 진행하던 프로젝트의 pom.xml을 그대로 가져와서 필요없는 것이 많길래 몇개를 제외시켰습니다.
2) yml 파일 설정
pring:
config:
activate:
on-profile: test
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://db:3306/test?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
username: root
password: 1234
dbcp2:
test-while-idle: true
jpa:
open-in-view: true
generate-ddl: true
hibernate:
ddl-auto: update
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
use-new-id-generator-mappings: true
properties:
hibernate:
# show_sql: true
format_sql: true
jackson:
serialization:
fail-on-empty-beans: false
output:
ansi:
enabled: detect
server:
port: 9000
servlet:
context-path: /
encoding:
charset: UTF-8
enabled: true
force: true
error:
include-message: always
중요하게 봐야하는 부분
url: jdbc:mysql://db:3306/test?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
원래는 굵은 글씨체로 되어있는 부분에 localhost라던지 다른 도메인 주소를 넣는다.
하지만 우리는 docker mysql image를 사용할 것이기 때문에 docker mysql image container 이름을 사용해준다.
docker와 통신을 하기 위해서는 container 이름을 이용하여 통신을 해야한다. !
custom docker network를 만들게 되면, container 생성시 부여한 이름으로 network 통신이 가능하다.
3) Entity 생성
import lombok.*;
import javax.persistence.*;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Entity
@Table(name = "auth_user")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false, name = "member_id")
private Long memberId;
@Column(name = "name")
private String name;
}
4) repository 생성
import com.gmc.dockertest.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MemberRepository extends JpaRepository<Member, Long> {
}
5) controller 생성
import com.gmc.dockertest.repository.MemberRepository;
import com.gmc.dockertest.entity.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class DockerController {
private final MemberRepository memberRepository;
@RequestMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/save")
public void test() {
Member m1 = Member.builder()
.name("정현진")
.build();
memberRepository.save(m1);
}
@GetMapping("/get")
public String getM1() {
return memberRepository.findAll().toString();
}
}
FROM adoptopenjdk/openjdk11
ARGJAR_FILE=target/*.war
COPY ${JAR_FILE} app.war
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=test","/app.war"]
java 11환경으로 실행시킬 것이고, target 경로에 있는 war파일을 app.war로 카피하여 실행시킨다.
profile를 설정하고 있지 않다면 -Dspring.profiles.active=test 이 옵션을 빼준다.
ARGJAR_FILE의 경로는 gradle일 때와 maven일 때 서로 다르다.
maven : target/*.war
gradle : /build/libs/*.war
maven package 를 이용하여 war파일을 생성한다.
target폴더 밑에 war파일이 생성된 것을 볼 수 있다.
컨테이너간 통신을 컨테이너의 이름으로 하기 위해서는, custom network를 생성하고, 해당 network에 container를 생성해야한다.
docker create network test
test 라는 network를 생성한다.
참고자료
Docker - Docker Network란? (Docker Netowkr 사용예제)
docker build -t [docker hub 아이디]/[docker hub repository 이름] --platform linux/amd64 .
뒤에 . 까지 꼭 ! 붙여줘야하며
mac m1 은 build시 --platform linux/amd64 문장을 넣어줘야 한다고 한다.
참고자료
https://github.com/JuHyun419/TIL-TodayILearned/issues/180
docker push [docker hub 아이디]/[docker hub repository 이름]
docker run --platform linux/amd64 -p 3306:3306 --name db -e MYSQL_ROOT_PASSWORD=1234
-e MYSQL_DATABASE=test -e MYSQL_PASSWORD=1234 -d --network test mysql
위 명령어를 이용해 mysql container를 우선 실행합니다. 원래는 이미지를 다운 받아야 하지만, 해당 이미지가 도커 호스트에 존재하지 않는경우, Docker가 자동으로 docker hub에서 찾고 존재한다면, 다운을 받아줍니다.
-d
: 백그라운드에서 container가 실행되도록 합니다.-e
: container 생성시 기본적으로 넘겨줄 파라미터를 지정합니다. 해당 mysql 이미지는 container 실행시, database root 관리자 비밀번호를 받도록 되어있습니다. Spring Boot Application을 생성할 때 Database 연결을 위해 지정한 비밀번호를 입력합니다.(1234)-p
: container가 외부에 노출할 port와 이 port에 연결하기 위해 docker host에서 사용할 port를 지정합니다.--network
: 우리가 생성한 custom network를 입력합니다.--name
: container에서 통신하기위해 사용할 이름을 부여합니다. Spring Boot Application을 생성할때 Database 연결을 위해 지정한 host 이름을 입력합니다. (db)참고자료
참고자료
docker exec -it db bash
exec
명령을 이용해, db
container에 연결함과 동시에 bash 셸을 실행 시킵니다.
user와 database가 있는 것을 확인하였다.
docker run -it --name app --network test -p 9000:9000 [docker hub 아이디]/[docker hub repository 이름]
bash
--network
옵션을 이용해 mysql container와 같은 network에 container를 실행시키며, Spring Boot application 생성시 application.yml에서 지정한 port를 외부로 노출합니다.
1) /hello 경로 확인
2) /save 경로 실행
3) /get 경로 확인
4) docker ps
0) war package
1) image build
2) docker push
3) docker run
docker mysql container로 실행시켰을 때 말고
로컬에서 테스트를 진행 중 다른 외부 서버 접속 비허용을 한 host로 접속을 했을 때와 똑같은 오류가 났다.
이때 들었던 생각으로는 외부 접속이 막혔다는 것은 프로젝트 컨테이너 실행과 데이터베이스 컨테이너 실행이 각각 다른 network에서 실행되고 있는 것이 아닐까 생각을 하였다.
하지만 나는 test라는 이름을 가진 network로 실행을 시켰던 것 같아서
다시 앞에서 실행했던 코드를 찬찬히 살펴보니 ..
여기서 network 설정을 안해주었던 것이다..!
그래서 mysql 컨테이너를 삭제후 다시 network 설정을 하여 실행했더니
잘 실행되었다.
휴 ~..
전체적인 참고 사이트 (생명의 은인들)
Docker - Spring Boot Application Docker로 배포하기 및 Mysql 연동
[Docker] 스프링부트를 docker 이미지를 통해서 AWS EC2에 배포하기(DockerHub)