5월19일시점 개발하면서 고민한 것들 + 도커관련 이슈
🤔 개요
프로젝트를 진행하면서 정말로 고민할 것들이 많아졌다.
지라의 티켓들인데 이걸보면 최근 고민이 진짜 많다.
😂 1. 토큰 만료시의 처리
내가 하고 있는 프로젝트는 refreshToken을 사용하지 않는다. AccessToken 하나만으로 고민을 해야하는데, 프로젝트 기간이 길어지면서 토큰 만료시간이 다 된 계정들이 몇 개 있었다.
이에 맞게 후처리를 해줘야하는데..
일단 토큰이 만료되면
1
2
3
4
5
6
7
8
9
{
"errors": {
"timestamp": "2023-05-19T00:36:31.8402904",
"status": 401,
"error": "UNAUTHORIZED",
"code": "UNAUTHORIZED_USER",
"message": "Unauthorized user. Please check your token."
}
}
이런 JSON이 클라이언트에 반환된다. 문제가 있다.
내가 옛날에 작성한 코드 https://kkminseok.github.io/posts/2023-03-11-SpringSecurityError/ 때문에 토큰에 문제가 생기면 무조건 401를 반환했는데, 토큰이 만료되었을때는 -1의 Status를 주고 싶었다.
문제는 Filter
에서 token검증을 하는데, 거기서 에러를 받고, 커스텀해서 -1의 상태를 가지는 ResponseEntity
객체를 주기가 불가능했다.
그래서 생각한건 Jwt관련 Controller
를 하나 만들어서 거기서 서비스를 호출하고 에러를 @ControllerAdvice
를 통해 전역으로 잡을까?
토큰하나때문에 컨트롤러 만드는것도 고민해야할 문제이고, 제대로 되지 않는다.
사실 이 부분은 계속해서 고민중이다.
😂 2. 클라이언트에 데이터를 어떻게 줘야할까?
나는 안드로이드 개발자와 협업하고 있다.
안드로이드 개발자와 이야기를 하다가 문제가 생겼다.
기존에는 데이터를 이런식으로 주고 있었다.
1
2
3
4
5
6
7
8
9
10
11
{
"questionBoardResponseList": [
{
"id": 18,
"slug": "hi",
"content": "hello",
"createdAt": "2023-05-18T23:27:45.437317+09:00",
"updatedAt": ...
}
...
}
근데 안드로이드 개발자는 결국 ‘questionBoardResponseList’를 key로 가지며 데이터를 파싱해야했고, ‘questionBoardResponseList’가 아닌 ‘questionBoardResponse’, ‘profileResponse’등 여러개들을 이름에 맞게 코드를 하나하나 다 작성해야했다.
그래서 처음 나온 의견은 아예 객체이름을빼자였다.
1
2
3
4
5
6
7
8
9
10
11
12
{
[
{
"id": 18,
"slug": "hi",
"content": "hello",
"createdAt": "2023-05-18T23:27:45.437317+09:00",
"updatedAt": ...
}
...
]
}
이런식으로.. 근데 문제는 딱 보이게도 배열은 배열로 받아야하고, 필드는 필드로 받아야한다. 그런 불편함이 생겨 우리 프로젝트에서는 객체 담아서 보내는게 맞다.고 결론이 내려졌다.
하나의 객체에 담겨서 보내주면 안드로이드에서 알아서 파싱해서 해결할 수 있다고 하길래 데이터를 data라는 객체에 담아 보내기로 했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"data":{
"questionBoardResponseList": [
{
"id": 18,
"slug": "hi",
"content": "hello",
"createdAt": "2023-05-18T23:27:45.437317+09:00",
"updatedAt": ...
}
...
}
}
이렇게 담아 보냈지만, 결국 파싱이 제대로 되지 않아서 해결되지 않았고 기존 방식대로 ‘questionBoardResponseList’ 키값을 그대로 파싱하기로 하였다.
근데 서버쪽에서 해결해줄 수 있는 더 좋은 방법이 있지 않을까? 고민하게 되었다. 안드로이드개발자와 협업하다보니 이런것을 고민하게 되었다.
😂 3. DELETE
Http Method는 꼭 데이터를 반환해야하나?
프로젝트를 하다가 다른 백엔드 개발자분께서 짜신 코드를 봤다.
간단하게 게시글을 좋아요, 좋아요 취소에 대한 API였다.
1
2
3
4
5
6
@DeleteMapping("/{studioId}/scrap")
public void deleteScrap(
@PathVariable Long studioId,
@AuthenticationPrincipal User user) {
scrapService.deleteScrap(studioId, user);
}
근데 나는 다른 방식으로 짰다.
1
2
3
4
5
6
7
@PostMapping("/{questionBoardArticleId}/unfavorite")
public QuestionBoardResponse.SingleQuestionBoard unfavoriteQuestionBoardArticle(
@AuthenticationPrincipal User user,
@PathVariable Long questionBoardArticleId) {
log.info("question board favorite input : {}", questionBoardArticleId);
return QuestionBoardResponse.SingleQuestionBoard.builder().questionBoardResponse(questionBoardService.unfavoriteQuestionBoardArticle(user, questionBoardArticleId)).build();
}
둘 다 같은 기능(좋아요, 좋아요 취소)이지만 짠 방식이 다르다.
- 나는
@PostMapping
을 사용하였다. - 나는 객체를 반환한다.
그래서 고민하게되었다. 나는 왜 @PostMapping
을 사용했을까? @DeleteMapping
이 맞나?
내 생각은 객체가 삭제되는건 아니고, 객체의 상태를 변경시키는거라고 생각해서 @PostMapping
을 달았고, 객체가 삭제되는게 아니기 때문에 객체를 반환했다.
그리고 생각했다. 요즘 Web Client기술은 객체의 상태를 추적해서 이에 맞게 계속 페이지를 렌더해주는걸로 알고 있다.
그래서 객체를 넘기면 반환된 객체의 상태가 계속 추적되어서 페이지뷰가 바뀐다.
근데 안드로이드에서는 그런 추적장치가 있느냐고 물어봤을때 잘 모르는걸로 봐서는 굳이 객체를 넘기지 않아도 되겠지만.. 그래도 객체가 삭제되는건 아니기에 객체의 상태를 개발자도 추적하기 위해서 넘기는게 맞지 않을까 라는 고민을 했다.
😂 4. Docker 이미지 관련 이슈
기존 CI/CD는 도커를 이용해서 이미지를 받아오고, 이를 컨테이너에 올리는 작업을 했는데
CI/CD과정속에서 계속 fail떴다.
왜지?
잘만되다가
처음에는 port가 겹쳐서 뜨나했다. 근데 이미 blue-green으로 배포하고 있기에 포트가 겹칠일이 없었다.
혹시 몰라서 인스턴스도 껐다켜보고 도커자체도 껐다가 켜보고 컨테이너도 다 내렸다가 올려보고 했다.
그래도 해결되지 않았다.
근데.. chatGPT선생님이 도커 용량이 꽉찼을 수도 있다하면서
1
sudo docker system df
이 명령어를 알려줬다.
이 명령어는 도커 용량을 확인할 수 있는데
1
2
3
4
5
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 19 1 1.493GB 1.426GB (95%)
Containers 1 1 32.77kB 0B (0%)
Local Volumes 0 0 0B 0B
Build Cache 7 0 131.7MB 131.7MB
지금은 어느정도 삭제한 상태지만 95%의 용량을 차지하고 있었고, 용량이 꽉차서 이미지를 받아오지 못하고, 그 과정속에서 CI/CD가 fail이 떠서 코드가 정상적으로 반영되지 않았던 것이다.
1
sudo docker images
이 명령어를 통해서 현재 저장된 도커 이미지들을 볼 수 있는데..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
REPOSITORY TAG IMAGE ID CREATED SIZE
teambpm2023/dnd-bpm main 3e0c053b8888 About an hour ago 538MB
teambpm2023/dnd-bpm <none> f4cf0812eeb0 2 hours ago 538MB
teambpm2023/dnd-bpm <none> 7233b8ffa465 3 hours ago 538MB
teambpm2023/dnd-bpm <none> 56e470449cf8 2 days ago 538MB
teambpm2023/dnd-bpm <none> 333eccb86ff5 5 days ago 538MB
teambpm2023/dnd-bpm <none> deda5288ced4 5 days ago 538MB
teambpm2023/dnd-bpm <none> 1aa6ad95bcb0 10 days ago 538MB
teambpm2023/dnd-bpm <none> 301b225bbd26 11 days ago 538MB
teambpm2023/dnd-bpm <none> c65082157308 11 days ago 538MB
teambpm2023/dnd-bpm <none> c189e6ca21c9 13 days ago 538MB
teambpm2023/dnd-bpm <none> 8fadb576b375 2 weeks ago 538MB
teambpm2023/dnd-bpm <none> 743ff80c1df1 2 weeks ago 537MB
teambpm2023/dnd-bpm <none> a1e19a5e3094 2 weeks ago 537MB
teambpm2023/dnd-bpm <none> 0dfd80b93183 3 weeks ago 537MB
web-green_nginx latest ba4e904a4efc 2 months ago 23.5MB
web-blue_nginx latest f56711d22b3e 2 months ago 23.5MB
ubuntu_nginx latest 65dcf19360e9 2 months ago 23.5MB
teambpm2023/dnd-bpm <none> 186805a54fe0 2 months ago 537MB
nginx 1.22.1-alpine 652309d09131 3 months ago 23.5MB
정말 별의별게 많다.
임시 방편으로
1
sudo docker image rm 이미지명
를 통해 이미지를 삭제해줄 수 있었다.
이게 중요한게 아니고, 결국 매번 이를 체크해서 지워줄 수는 없는 노릇이니 CI/CD를 구축할때 기존 이미지를 지워주고 이미지를 받아야겠더라.
이를 티켓을 끊어서 곧 해결하고 배포할 예정이다.
추가
이는 간단하게 해결할 수 있다.
배포파일에다가
1
2
3
4
5
6
7
#최근 받은 이미지를 삭제할 변수 설정
LATEST_IMAGE=$(sudo docker images --format "" --quiet | head -n 1)
#확인용 출력
echo "LATEST_IMAGE value is: $LATEST_IMAGE"
#이미지 삭제
sudo docker image rm $LATEST_IMAGE
이렇게 작성하면된다.
주의할 점은 이미지가 이미 컨테이너로 띄워져있으면 삭제가 안 되기 때문에 컨테이너가 종료되고 나서 이미지를 삭제해야한다는 것이다.