728x90

 

 

 오늘도 퇴근하고 알고리즘 문제를 풀다가 글또 신규 기수 모집에 대한 메일을 받았고, 신청을 하기 위해 답변들을 작성하다 삶의 지도라는 항목을 발견했습니다.

 

 시간이 늦어서 아침에 일어나 작성할까 했지만, 자신의 삶을 돌아보기에는 감성이 넘치는 저녁 시간대가 가장 좋다고 생각이 들었기 때문에 지금부터 저도 아직 잘 알지 못하는 제 자신을 돌아보겠습니다!

 

 

나는 어떤 사람일까?

 제 좌우명은 '남에게 피해 주지 않고 누구보다 게으르게 살자'입니다. 평생을 공부해야 하는 개발자라는 직업을 하기에는 어울리지 않다고 볼 수도 있습니다. 학창 시절에도 공부를 열심히 한 것도 아니고, 그렇다고 노는 것을 제대로 논 것도 아닌 남들에게 피해 주지 않는 선에서 제 스스로의 일에는 한없이 게으르게 살아왔습니다.

 

첫 프로젝트

 언어나 이론적인 학습이 아닌, 처음으로 무언가를 만든 것은 대학교 4학년 때입니다. 컴공생이 4학년에서야 처음으로 무언가를 만들어 봤다는 게 잘못된 거긴 하지만 당시에는 하고 싶은 것도 없었고, 졸업만 하자는 생각으로 의미 없이 학점만 채우고 있었습니다.

 

 그렇게 4학년 때 졸업 프로젝트로 친구와 둘이서 처음으로 웹 프로젝트를 진행하게 되었습니다. 웹 개발이라는 것을 해본 적이 없으니 당연히 시작부터 막힐 수밖에 없었고, 처음에는 스트레스를 받으며 무작정 들이박으면서 돌아가기만 하는 웹이라고 할 수 없는 무언가를 만들어가고 있었습니다.

 

 하지만 어느 순간부터 스트레스보단 즐거움이 더 커졌던 것 같습니다. 발생한 문제나 모르는 것들을 조사해 가며 해결해 가는 과정도, 점점 완성도가 높아져가는 프로젝트를 지켜보는 것도, 친구와 밤샘 코딩 하고 밤낮이 바뀐 삶을 사는 것마저도 하나하나 모두 즐겁게 느껴졌고, 마지막에는 동기들 앞에서 프로젝트를 발표하는 순간에 느낀 성취감과 뿌듯함까지 살면서 이렇게 무언가를 재밌고 열심히 해본 경험이 처음이었습니다.

 

 

웹 개발을 제대로 배워보자

 하지만, 졸업 프로젝트라고 해봤자 대환장 파티가 열린 코드로 어떻게든 돌아가는 웹을 만든게 전부였고, 웹 개발이 재밌었기 때문에 제대로 배워보고 싶다는 생각이 들어서 졸업 후에 부트캠프를 수강하게 되었습니다.

 

 본가가 강릉이다 보니 온라인으로 들을 수 밖에 없었고, 온라인이다 보니 오로지 혼자서 집중하고 학습해야 했기에 수강 초기에는 많이 흔들렸습니다. 그러던 와중에 동기들끼리 소규모로 스터디를 진행하게 되면서 같이 목표를 정하고, 모르는 것을 물어보고, 발표하는 시간들을 가지면서 집중도 잘 유지할 수 있었고 즐겁게 학습할 수 있었습니다.

 

 또한, 온라인으로 진행하다보니 정말 다양한 사람들을 만날 수 있었습니다. 나이가 많으신 분임에도 개발이라는 분야에 도전하시는 분, 개발자가 적성에 맞지 않아서 힘들어하시지만 개발이 좋아서 밤늦게까지도 누구보다 열심히 하시던 분 같은 여러 사람들을 만나면서 동기 부여에 큰 힘이 되었고, 개발이라는 분야에 대해서 내가 너무 가볍게 생각하고 있지 않았나 돌아볼 수 있었습니다.

 

취업을 준비하며

 부트캠프를 수강하고 난 후에는 동기 몇 분들과 함께 알고리즘과 면접 스터디를 진행하며 취업을 준비하게 되었습니다. 하지만, 막상 취업을 준비하기만 하고 이력서를 넣지는 않고 있었는데, 당시에 취업을 하기에는 스스로에게 자신감도 없고 두려웠던 것 같습니다. 그래서 결국에는 큰맘 먹고 이력서를 열심히 써서 내기 시작했는데 결과 통보조차 없거나 떨어졌다는 결과만 받아 면접조차 보지 못하고 있었고, 갈수록 자신감만 떨어져 이력서를 내는 것을 멈추게 되었습니다.

 

 그러다가 한 회사에서 면접을 보러 오라는 연락이 왔고 제 인생 처음으로 면접을 보게 되었습니다. 결과는 당연히 불합격이지만, 그동안 취업을 준비하며 궁금 했던 것들도 물어보고, 선배 개발자 분들에게 회초리도 맞으면서 저의 방향성이 잘못되었단 걸 알았습니다.

 

 당시에 최근에는 어떤 것을 하고 있는지에 대해 이야기를 하다가 '개발을 좋아하신다면서 프로젝트를 추가로 하고 계시지는 않네요' 라는 말씀을 들었는데, 면접이 끝나고 집으로 돌아가는 길에 개발자는 결국 코드로 말하는 사람이고, 스스로 개발을 좋아한다면서 부트캠프 이후에 현재까지 다섯 달 동안 시간이 없던 것도 아니면서 취업 준비를 핑계로 개발을 손에서 놓고 있던 스스로가 부끄럽게 느껴졌습니다.

 

 

현재는

 현재는 다시 정신차리고 열심히 이력서를 넣어 인생 첫 직장을 가질 수 있었고, 낯 가림이 많지만 좋은 팀원들을 만나 잘 적응하며 즐겁게 회사를 다니고 있습니다. 사실 아직도 완전히 적응한 것은 아닌 덤벙대는 4개월 차 신입입니다.

 

 최근에는 기존에 얹혀 살던 이모네 집을 나와 회사 근처에 원룸을 구해 강원도에서만 살던 촌놈이 도시에서 혼자 처음으로 자취를 하고 있습니다. 이제 좀 삶적으로 여유가 생겨 유일한 습관이었던 하루에 알고리즘 하나 풀기 외에도 현재 쉬고 있는 블로깅도 다시 시작하고, 간단한 운동, 짧은 독서 등 좋은 습관들을 하나씩 늘려나가며 정상인(?)처럼 살아보려 합니다.

'Diary' 카테고리의 다른 글

블로깅 돌아보기  (0) 2024.11.24
10일 동안 글자 하나 안 쓴 사람의 다짐글  (1) 2024.10.08
백준 근황  (0) 2024.07.27
솔브닥 마라톤 1코스 완주  (0) 2024.06.09
[백준] 골드1 달성!  (0) 2024.03.14
728x90

 

 

드디어 스트릭 300대 진입...!

 

요즘은 정신이 없어서 매일 출근해서나 아니면 퇴근하고 마라톤만 한 문제씩 풀고 있는데

랜덤이다보니 백준에서 가장 많은 문제를 보유한 수학 태그들이 자주 나와서 머리가 아프다

 

수학이 약해서 정수론, 기하학 이런 태그 붙은 문제들 나오면 해당 문제들은 그냥 넘겨버렸는데

최근에 톱니바퀴를 눌러보니 마라톤 문제 리셋 기능이 추가되어 있었다...

 

수학도 언젠간 공부해야하지만 지금은 다른거 공부하기도 바쁘기 때문에 일단은 돌리고

나중에 여유가 생기면 다시 공부를 해서 밀어두었던 수학 문제 폭탄들을 감당하는걸로...

'Diary' 카테고리의 다른 글

10일 동안 글자 하나 안 쓴 사람의 다짐글  (1) 2024.10.08
삶의 지도  (0) 2024.09.12
솔브닥 마라톤 1코스 완주  (0) 2024.06.09
[백준] 골드1 달성!  (0) 2024.03.14
새로 추가된 언어 뱃지들  (0) 2024.02.23
728x90

문제

 

접근 방식

처음에는 이름이랑 그림만 보고 트리 문제인가 했는데 읽고서 그림을 그려보다 보니 DP 문제에 가까워 보였다.

 

근데 막상 DP를 사용해서 풀지도 않았고 이게 왜 티어를 골드 4까지나 준건지 모르겠는 문제인데, 규칙만 찾으면 코드 몇 줄로도 간단하게 풀 수 있다.

 

아래에서부터 왼중오 3개의 노드를 하나의 차로 방문하는 것이 가장 적은 차를 사용하는 경우이고, 주어진 입력내 트리의 노드 수가 long의 범위를 벗어나지 않기 때문에 DP를 사용하지 않고도 단순 연산으로도 풀 수 있다.

 

풀이

public class Main {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int h = Integer.parseInt(br.readLine());

		long road = (2L << h) - 1;

		long result = road % 3 != 0 ? road / 3 + 1 : road / 3;

		System.out.println(result);
	}
}

 

728x90

 

이번에 새로운 시즌이 종료되면서 랜덤 마라톤이라는 시스템이 추가되었는데

자신의 현재 티어에 맞게 완전히 랜덤으로 문제를 추천해준다.

 

기존에는 포인트 획득 경로가 매일 첫 문제 75점과 문제당 25점이라 모으기 쉽지 않았지만

이번 마라톤 시스템은 포인트 보상을 달달하게 챙겨줘서 포인트 모으기가 수월해졌다.

 

언어 설정이 있는줄 모르고 일본어랑 영어 문제들을 번역기 써가며 다 풀고 보니

작은 톱니바퀴 아이콘을 오늘에서야 봤다...

 

영어는 익숙해져서 나쁠게 없으니 다음 코스부턴 일본어만 제외하고 문제를 풀어봐야겠다.

 

사실 그래프, 백트래킹, 해쉬 같은 문제들만 좋아해서 그리디, DP 같은 것들에 약하긴 했는데

매일 스트릭 유지도 하고 알고리즘 편식도 고칠겸 매주 완주를 목표로 해야겠다.

'Diary' 카테고리의 다른 글

삶의 지도  (0) 2024.09.12
백준 근황  (0) 2024.07.27
[백준] 골드1 달성!  (0) 2024.03.14
새로 추가된 언어 뱃지들  (0) 2024.02.23
[백준] 128일 뱃지  (0) 2024.02.07
728x90

QClass

// import static com.~.~.~.~.QCustomer.*;
QCustomer customer = QCustomer.customer;
QCustomer customer = new QCustomer("myCustomer");

 

실제 도메인 클래스의 질의 타입으로 정적으로 사용하거나 별칭을 붙여 사용할 수 있다.

 

쿼리 사용해 보기

JPAQuery<?> query = new JPAQuery<Void>(entityManager);
HibernateQuery<?> query = new HibernateQuery<Void>(session);

 

JPA와 Hibernate API를 모두 지원하기 때문에 위와 같이 둘 다 사용 가능하고

두 클래스 모두 JPQLQuery 인터페이스의 구현체다.

QCustomer customer = QCustomer.customer;
Customer bob = queryFactory.selectFrom(customer)
  .where(customer.firstName.eq("Bob"))
  .fetchOne();

 

두 쿼리 인스턴스 모두 주로 JPAQueryFactory(혹은 Hibernate)를 통해서 생성할 수 있다.

위의 코드의 과정을 간략하게 정리하면

쿼리 팩토리로.(지정한 컬럼과 테이블의 결과를 하나만 반환하는) 쿼리를 만든다.

라고 할 수 있다.

select customer from Customer as customer
where customer.firstName = "Bob" or customer.lastName = "Wilson"

 

예를 들어 위의 쿼리문을 QueryDSL로 작성하면

queryFactory.selectFrom(customer)
    .where(customer.firstName.eq("Bob").or(customer.lastName.eq("Wilson")));

 

이러한 코드를 작성할 수 있는데 실제 쿼리문과 유사한 형태에 IDE를 통한 자동완성과

문법 체크의 도움을 받아 편리하고 안정적이게 작성할 수 있게 된다.

 

조인

QueryDSL도 마찬가지로 JPQL에 있는 다양한 조인들을 지원한다.

select cat from Cat as cat
inner join cat.mate as mate
left outer join cat.kittens as kitten

 

예를 들어 위와 같이 동일한 테이블을 조인한다고 했을 때는

QCat cat = QCat.cat;
QCat mate = new QCat("mate");
QCat kitten = new QCat("kitten");

 

테이블의 별칭을 다르게 만들고

queryFactory.selectFrom(cat)
    .innerJoin(cat.mate, mate)
    .leftJoin(cat.kittens, kitten)
    .fetch();

 

서로 같은 컬럼을 기준으로 조인을 하는 경우에는 mySQL의 using처럼

on절을 사용하지 않고도 조인을 할 수 있고

별도의 조건으로 조인을 하는 경우에는 다음과 같이 on절을 사용하면 된다.

queryFactory.selectFrom(cat)
    .leftJoin(cat.kittens, kitten)
    .on(kitten.bodyWeight.gt(10.0))
    .fetch();

 

일반적인 사용

  • select : 쿼리의 프로젝션을 설정한다.
  • from : 쿼리의 소스를 추가한다.
  • join : innerJoin, join, leftJoin, rightJoin, on을 사용하여 조인 요소를 추가할 수 있고, 조인 메서드의 첫 번째 파라미터는 원본, 두 번째 파라미터는 조인 대상이 된다.
  • where : 쿼리의 필터를 추가한다. 쉼표 혹은 and 연산자를 통해 계단식으로 배열한다.
  • groupBy : 그룹화 조건으로 사용할 파라미터를 추가한다.
  • having : 그룹화 대상이 갖고 있어야 할 파라미터를 추가한다.
  • orderBy : 정렬 기준으로 사용할 파라미터를 추가한다.
  • limit, offset, restrict : 페이징의 결과를 설정한다.

 

정렬

QCustomer customer = QCustomer.customer;
queryFactory.selectFrom(customer)
    .orderBy(customer.lastName.asc(), customer.firstName.desc())
    .fetch();

 

orderBy 메서드의 파라미터로 정렬 기준이 될 컬럼과 정렬 방식을 전달해 주면 된다.

 

그룹화

queryFactory.select(customer.lastName).from(customer)
    .groupBy(customer.lastName)
    .fetch();

 

그룹화도 마찬가지로 groupBy 메서드의 파라미터로 기준을 전달해 주면 된다.

 

삭제절

QCustomer customer = QCustomer.customer;
queryFactory.delete(customer).execute();
queryFactory.delete(customer).where(customer.level.lt(3)).execute();

 

데이터의 삭제는 delete - (where) - execute 형식으로 이루어져 있는데

where 절을 생략하면 해당 테이블의 모든 데이터를 삭제하는

JPA로 치면 deleteAll 메서드에 해당한다.

 

execute가 호출되면서 실제 데이터가 삭제되고 삭제된 엔티티의 수를 반환한다.

 

JPA의 DML 절은 JPA 레벨의 영속성 전파 규칙을 따르지 않고, 2차 레벨 캐시와 연동되지 않는다.

 

수정절

QCustomer customer = QCustomer.customer;
queryFactory.update(customer).where(customer.name.eq("Bob"))
    .set(customer.name, "Bobby")
    .execute();

 

수정도 비슷하게 update - (where) - set - execute 형식으로 이루어져 있다.

 

마찬가지로, JPA의 DML 절은 JPA 레벨의 영속성 전파 규칙을 따르지 않고, 2차 레벨 캐시와 연동되지 않는다.

 

서브쿼리

QEmployee employee = QEmployee.employee;
QEmployee e = new QEmployee("e");
queryFactory.selectFrom(employee)
    .where(employee.weeklyhours.gt(
        JPAExpressions.select(e.weeklyhours.avg())
            .from(employee.department.employees, e)
            .where(e.manager.eq(employee.manager))))
    .fetch();

 

서브쿼리는 정적 팩토리 메서드인 JPAExpression를 통해 사용할 수 있다.

기존 방식과 마찬가지로 select, from, where절 등을 활용하여 서브쿼리를 작성하면 된다.

 

쿼리 내보내기

Query jpaQuery = queryFactory.selectFrom(employee).createQuery();
// 쿼리 조정 및 최적화 등
List results = jpaQuery.getResultList();

 

createQuery 메서드를 사용해 쿼리문을 생성할 수 있고, 이 작업은 실제로 쿼리를 날리는 것이 아니라

쿼리문을 만들어두기만 한 상태이기 때문에 추가적인 작업을 거친 후에

getResultList 같은 메서드를 호출하여 완성된 쿼리를 실제로 날려서 데이터를 조회할 수 있다.

728x90

문제

 

 

접근 방식

인접 리스트를 만든 후에 일반적인 그래프 탐색으로 여행 경로를 모두 이동해보면

시간 초과가 발생하기 때문에 여행 경로가 모두 한 사이클에 포함 되는지만 파악하면 된다.

 

이럴 때 효율적인 알고리즘이 유니온 파인드인데

유니온 함수를 이용해 연결된 정점들끼리의 부모를 기록해두고

파인드 함수를 이용해 서로의 최고 조상이 누구인지 확인하여

같은 사이클에 존재하는지 여부를 빠르게 판단할 수 있다.

 

초기에는 각 도시마다 자기 자신을 부모로 초기화하고

주어진 도시 간의 경로를 유니온 함수로 연결한 후에

여행 경로대로 파인드 함수를 사용해 모두 하나의 사이클에 포함되는지 확인한다.

 

풀이

public class Main {

	static int[] parent;

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;

		boolean isPossible = true;
		int n = Integer.parseInt(br.readLine());
		int m = Integer.parseInt(br.readLine());
		parent = new int[n + 1];

		for (int i = 1; i <= n; i++) {
			parent[i] = i;
		}

		for (int i = 1; i <= n; i++) {
			st = new StringTokenizer(br.readLine());

			for (int j = 1; j <= n; j++) {
				if (Integer.parseInt(st.nextToken()) == 0) continue;
				union(i, j);
			}
		}

		st = new StringTokenizer(br.readLine());
		int x = find(Integer.parseInt(st.nextToken()));

		for (int i = 1; i < m; i++) {
			if (find(Integer.parseInt(st.nextToken())) != x) {
				isPossible = false;
				break;
			}
		}

		System.out.println(isPossible ? "YES" : "NO");
	}

	static void union(int x, int y) {
		x = find(x);
		y = find(y);

		if (x != y) parent[y] = x;
	}

	static int find(int x) {
		if (parent[x] == x) return x;
		return parent[x] = find(parent[x]);
	}
}

 

728x90

문제

 

 

접근 방식

그래프 문제도 아니고 그냥 일반적인 반복문 문제라

입력 받고 8방향 중 한 방향으로 4개의 알파벳들이 각각 O B I S인지 모두 확인해주면 된다.

 

문자 배열을 미리 만들어두고 비교를 했는데 목표 단어에 중복된 문자가 존재하지 않아서

애초에 M을 1, O를 2, ..., S를 5로 두고 증가하는 순으로 비교하면 더 깔끔할거 같다.

 

풀이

public class Main {

	static int n, cnt = 0;
	static char[] chars = new char[]{'O', 'B', 'I', 'S'};
	static char[][] map;
	static int[] dx = {-1, -1, -1, 0, 0, 1, 1, 1};
	static int[] dy = {-1, 0, 1, -1, 1, -1, 0, 1};

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		n = Integer.parseInt(br.readLine());
		map = new char[n][n];
		Queue<Pair> q = new LinkedList<>();

		for (int i = 0; i < n; i++) {
			String str = br.readLine();

			for (int j = 0; j < n; j++) {
				char c = str.charAt(j);
				map[i][j] = c;
				if (c == 'M') q.offer(new Pair(i, j));
			}
		}

		while (!q.isEmpty()) {
			Pair cur = q.poll();

			for (int dir = 0; dir < 8; dir++) {
				int nx = cur.x + dx[dir] * 4;
				int ny = cur.y + dy[dir] * 4;

				if (nx < 0 || ny < 0 || nx >= n || ny >= n) continue;

				int x = cur.x + dx[dir];
				int y = cur.y + dy[dir];

				for (int i = 0; i < 4; i++) {
					if (map[x][y] != chars[i]) break;
					x += dx[dir];
					y += dy[dir];
					if (i == 3) cnt++;
				}
			}
		}

		System.out.println(cnt);
	}


	static class Pair {
		int x, y;

		public Pair(int x, int y) {
			this.x = x;
			this.y = y;
		}
	}
}

 

728x90

개요

우선 처음 사용해보고 느낀 점은 초기 셋팅할 때 햇갈린거만 빼면 생각보다 어렵지 않다는 것이다.

 

워낙 유명한 툴이다 보니 인터넷에 정보도 많고 다양한 플러그인과 GUI 덕분에 처음 사용해보는 사용자도

어려움 없이 사용할 수 있는거 같다. 물론 어느 정도 스크립트를 작성하긴 해야한다.

 

아마 이전에 Github Actions를 사용해본 사람이라면 스크립트를 짜는 것이 어렵진 않을거다.

 

CI/CD Pipeline

당장은 EC2 인스턴스는 Jenkins 서버용과 SpringBoot 서버용으로 두 개만 사용 중이고

프로젝트가 어느 정도 완성되어 가면 추후에 아키텍처를 수정할 생각이다.

 

Jenkins는 도커를 사용해 환경을 구성하는게 편해 해당 방식을 사용했고

이후에 도커 이미지 빌드와 푸쉬를 위해 Docker를 사용해야 하지만

Jenkins 컨테이너에 Docker를 또 설치하는 것은 비효율적이라

호스트의 도커 소켓을 컨테이너와 공유하여 사용하게 컨테이너를 띄웠다.

 

배포 서버는 도커만 설치하여 Jenkins에서 CD 작업을 수행할 때

새로운 이미지로 컨테이너를 띄울 수 있게 구성했다.

 

 

Jenkins Pipeline

프리스타일 프로젝트를 사용해서 간단하게 만들 수도 있지만 Pipeline 방식이 뭔가 더 끌려서

해당 방식을 사용하게 되었는데, 이전에 Github Actions를 사용해봐서 그런지 생각보다 익숙했다.

 

Github보다 환경 변수나 인증 정보들을 관리하기도 더 편리하고, 아직 많은 플러그인을 사용해보진 못했지만

도커 이미지를 관리하거나 배포 서버의 SSH에 접근하는 것이 좀 더 간결하게 가능한거 같다.

 

 

Webhook

사실 개인적으로 가장 마음에 들었던 것은 이 웹훅인데 레포지토리에서 특정 동작이 수행될 때

Jenkins 서버에 웹훅을 날리게 되고 이때 받는 정보들을 사용해 하나의 파이프라인으로

여러 상황에서 공통적으로 사용할 수 있다는게 Github Actions와 비교 했을 때 좋다 생각한다.

 

Github Actions는 작성한 워크플로우가 해당 레포지토리에만 적용이 되는데

Jenkins는 웹훅을 통해 얻는 정보로 브랜치나 레포지토리 단위로 재사용을 할 수 있다.

 

 

사용한 Pipeline 예제

pipeline {
    environment {
        DOCKERHUB_CREDENTIALS = credentials('docker_hub')
        AWS_URL = '배포 서버의 EC2 IP'
    }
    
    agent any

    stages {        
        stage('Checkout') {
            steps {
                git branch: 'main', 
                    credentialsId: 'git_id', 
                    url: '깃허브 레포지토리 주소'
            }
        }
        
        stage('Test') {
			steps {
				dir('디렉토리가 다른 경우') {
					sh "chmod +x ./gradlew"
					sh "./gradlew clean test"
				}
			}
		}
        
        stage('Build') {
			steps {
				dir('디렉토리가 다른 경우') {
					sh "chmod +x ./gradlew"
					sh "./gradlew bootJar"
				}
			}
		}
		
		stage('JUnit') {
			steps {
				dir('디렉토리가 다른 경우') {
					junit '**/build/test-results/test/*.xml'
				}
			}
		}
		
		stage('Docker Build and Push') {
			steps {
				dir('kko-kko-noodles') {
				    sh 'docker login -u $DOCKERHUB_CREDENTIALS_USR -p $DOCKERHUB_CREDENTIALS_PSW'
					sh 'docker build -t 이미지명:$BUILD_NUMBER .'
					sh 'docker push 이미지명:$BUILD_NUMBER'
					sh "docker rmi 이미지명:$BUILD_NUMBER"
				}
			}
		}
		
		stage('Run'){
            steps{
                blueDeploy(AWS_URL)
            }
        }
    }
}

def blueDeploy(awsUrl){
    sshagent(['ec2_blue']) {
        sh """
            ssh -o StrictHostKeyChecking=no ubuntu@${awsUrl} '
                docker login -u $DOCKERHUB_CREDENTIALS_USR -p $DOCKERHUB_CREDENTIALS_PSW
                docker stop \$(docker ps -a -q)
        		docker rm \$(docker ps -a -q)
                docker rmi \$(docker images -q)
        	    docker pull 이미지명:$BUILD_NUMBER
        		docker run -d -p 80:8080 --name 컨테이너명 이미지명:$BUILD_NUMBER
    		'
		"""
    }
}

 

 

마치며

 

 

컨테이너를 잘못 만들어서 중간에 날리고 다시 만든 후에 19번 만에 마칠 수 있었는데

왜 벌써 해가 뜰 시간이 다가오는 것인지...

'Back-End' 카테고리의 다른 글

HTTP  (0) 2023.05.23

+ Recent posts