728x90

Jenkins란?

  • 오픈소스 자동화된 서버(controller / master)
  • 자동화된 CI/CD 도구 : DevOps integrator
    • building, testing,delivering, deploying s/w
  • 1000개 이상의 plugin, Java 기반
  • maven/java project와 맞는다

장점

  • 개발자에게 빠른 피드백
  • 개발자가 문제를 찾고 고치기에 쉬움
  • 개발자 생산성 향상
  • 코드 퀄리티 향상
  • integration 과정을 자동화함
  • s/w release 프로세스 자동화
  • s/w 업데이트 release를 더 빠르게 할 수 있다.
  • Jenkinsfile을 통한 자동화된 CI/CD pipeline

Jenkins 특징

  • Jetty web server에 연동되어 웹서비스 형식으로 Jenkins 서비스 제공
    • Jenkins를 깔면 jetty가 같이 깔리고 request는 웹서버로 온다.
    • default port #가 8080
    • 실제에서 jenkins를 사용할때 기기이름:8080을 하면 jetty라는 서버가 받는다.
    • Jenkins가 일을 하고 최종 결과를 html로 바꾸는 역할을 한다.
  • Maven 등 build tool 연동
  • Selenium 등 test tool 연동
  • Container를 k8s cluster에 deploy
  • 1000개 이상의 자동화 툴 plugin 존재
  • 다양한 notification 툴 연동 - Jabler, IRC, Desktop notification …
728x90

문제 상황

Jenkins가 설치된 EC2 인스턴스를 중지 후 시작하자 Jenkins 웹서비스의 속도가 너무 느려짐

발생 이유

AWS Free Tier를 사용하는 경우 EC2 인스턴스를 중지 후 시작하면 public ip가 변경되는데 이를 설정해줘야함.

해결 방안

  1. Jenkins dashboard > Jenkins 관리 > System에서 Jenkins Location을 찾아야한다.
  2. Jenkins URL을 http://[EC2 인스턴스의 public ip]:8080 으로 변경해준다.
    왜냐하면 이 값은 중지 이전 public ip로 설정되어 있기 때문이다.

'개발 > CICD' 카테고리의 다른 글

Jenkins (1) - Jenkins란?  (0) 2024.06.03
Jenkins (3) - Java Project build with Maven  (1) 2024.06.03
Jenkins (2) - 설치  (1) 2024.06.03
728x90

EC2 instance를 중지 후에 다시 재개 해서 public ip가 변경되어도 동일하게 [public ip]:8080으로 접근하면 된다.

Java project를 build하는데는 maven을 사용하는게 보편적이었다. (요새는 Gradle 많이 씀)

우리는 Java project를 build 하기 위해 Jenkins에서 제공하는 샘플 Java code를 사용합니다.

🔥링크🔥

코드 확인

Simple Java Maven App

App.java

src 디렉토리를 가면 main, java 디렉토리가 있다.

main의 App.java 코드를 확인하면 진짜 기본적인 코드가 있다. (그냥 Hello world! 출력)

pom.xml

  • maven은 pom.xml 파일을 보고 java source code를 실행하는데 필요한 정보를 확인한다. dependency등.. (pom = project object model)
  • dependcy를 확인하면 junit이라는 도구가 있는데 이는 test시에 필요하다.
  • 본 코드에서는 test/AppTest.java를 unit test하는 코드가 있는데 여기서 활용한다. (@Test 어노테이션을 사용하기 위해 필요)
  • xml 파일 하단에 보면 Maven 버전도 확인이 가능하다.

maven 확인

위의 repository를 clone한 디렉토리에 들어가서 maven package를 하게 되면 java program이 실행될 수 있는 executable이 java 파일로 생성된다.

1. 수작업으로 Maven으로 Java Project Build하기

Git 설치

sudo apt-get update
sudo apt-get install git
sudo apt-get update
sudo systemctl daemon-reload

Maven 설치

mvn -v

위 코드로 maven 설치 여부를 확인한다. 아직 설치가 되어 있지 않으므로 아래와 같은 문구가 출력된다.

Command 'mvn' not found, but can be installed with:
sudo apt install maven

위 명령어를 사용하면 maven이 설치가 된다. 하지만, maven은 linux 운영체제에 의해 기본적으로 제공되는 프로그램이 아니고 third party 프로그램이다.

따라서, 이렇게 설치를 하게 되면 apt 리포지토리가 아는 maven을 설치하게 된다.

하지만 maven 특정 버전이라고 명시를 해주지 않으면 3.6 버전을 가져오게 된다. (우리에게 필요한건 3.8.6 이상.. 그냥 최신거 쓰면 됨)

따라서 우리는 이 🔥링크에 들어가서 설치를 하면 된다.

문제는 ubuntu에 설치해야하므로 curl이나 web get 하면 된다.

왼쪽 네비게이션 탭의 download에 들어가서 링크 주소를 복사한다.

[링크 주소] https://dlcdn.apache.org/maven/maven-3/3.9.7/binaries/apache-maven-3.9.7-bin.tar.gz

Maven 설치

linux에서는 s/w를 설치 할 때 관습적으로 특정 경로 ( /local or /opt ) 에 설치한다.

admin이 해당 s/w를 확인하고 ubuntu linux에 tight하게 bind 되어 있다면 /usr/local에 설치한다.

linux와 상관 없는 third party program은 /opt에 설치한다.

따라서, 우리는 /opt 폴더에 설치한다.

cd /opt
sudo wget <https://dlcdn.apache.org/maven/maven-3/3.9.7/binaries/apache-maven-3.9.7-bin.tar.gz>
sudo tar -xvf apache-maven-3.9.7-bin.tar.gz
sudo ln -s /opt/apache-maven-3.9.7 /opt/maven
sudo vi /etc/profile.d/maven.sh

이후 maven.sh 파일 안에 아래 문구를 추가한다.

export M2_HOME=/opt/maven
export MAVEN_HOME=/opt/maven
export PATH=${M2_HOME}/bin:${PATH}

아래 명령어를 마저 입력하고 mvn -v 로 maven 설치를 최종 확인한다.

sudo chmod +x /etc/profile.d/maven.sh
source /etc/profile.d/maven.sh
mvn -v

git clone

cd ~
mkdir maven-test && cd maven-test
git clone <https://github.com/jenkins-docs/simple-java-maven-app.git>

MVN complie

cd simple-java-maven-app
ls -al
mvn compile

mvn compile을 하면 많은 것들을 compile하고 download한다.

MVN Test

mvn test

우리는 미리 정의된 AppTest 파일이 있기 때문에 maven이 test 과정을 수행한다.

MVN Package

mvn package
ls -al

프로그램을 실행파일로 만드는 즉, package로 만드는 명령어.

이후 ls -al 로 파일 목록을 확인하면 target이라는 디렉토리가 생성된걸 확인할 수 있다.

maven이 target이라는 디렉토리를 만들어서 그 안에 실행파일을 넣은 것이다.

jar 파일 실행

java -jar my-app-1.0-SNAPSHOT.jar

위 명령어로 jar 파일을 실행하면 “Hello World!”가 출력되는 것을 확인할 수 있다.

2. Jenkins 활용해서 Maven 활용해서 Java Project build하기

Jenkins 관리 > Tools

나머지 건드리지말고 Maven Installation만 수정

Maven Installation

이름 설정. 개인적으로 mvn-3.9.7이라고 함

버전은 그대로 3.9.7

우리는 이미 maven을 설치했으므로 install automatically 체크 해제한다.

MAVEN_HOME

이 값으로는 /opt 폴더의 apache-maven-3.9.7 디렉토리의 주소를 전달하면 된다.

/opt/apache-maven-3.9.7

이후에 save하면 된다.

새로운 item 생성

이제 maven이라는 도구를 등록했으므로 새로운 item을 생성한다

item 이름은 개인적으로 설정(나는 simple-java-maven-app)

이후 freestyle project를 생성한다.

Configure

repository url

앞선 실습에서는 github에서 직접 ec2 인스턴스에 clone을 해서 작업을 했는데 이를 자동화한다.

우리는 소스코드를 github로부터 가져오므로 소스코드 관리에 github 리포지토리 url을 추가한다. <>code 부분 누르면 나오는 주소를 입력하면 된다. https://github.com/jenkins-docs/simple-java-maven-app.git

credentials

github의 코드를 가져올때 리포지토리가 private이라면 접근 권한을 추가해야한다.

우리는 public repository니까 none으로 유지한다.

Build Step

나머지는 다 스킵하고 build step으로 넘어간다.

invoke top-level maven targets를 설정한다.

maven version

우리는 3.9.7 버전을 설치하였으므로 설정한다.

Goals

우리의 목표는 java package를 만드는 것이므로 package라고 설정한다.

이후 저장한다.

빌드

좌측 네비게이션 탭에서 지금 빌드를 클릭한다.

빌드 결과

이후 좌하단 초록색 체크표시 링크를 클릭하면 console output을 확인 할 수 있다.

매우 길다.

jar 파일 생성 확인

console output을 쭉 내려보면 jar 파일의 경로를 확인할 수 있다.

 

해당 경로 ( /var/lib/jenkins/workspace/simple-java-maven-app/target/ ) 으로 이동해서 jar 파일을 실행해보자

ls -al
java -jar my-app-1.0-SNAPSHOT.jar

그러면 출력 결과로 “Hello World!”를 확인 할 수 있다.

 

'개발 > CICD' 카테고리의 다른 글

Jenkins (1) - Jenkins란?  (0) 2024.06.03
Jenkins Trouble Shooting - (1) 웹페이지 속도 저하 해결  (0) 2024.06.03
Jenkins (2) - 설치  (1) 2024.06.03
728x90

환경

AWS EC2 instance - free tier(t2.micro)

Ubuntu 24.02

Jenkins 설치

sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \\
  <https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key>
echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]" \\
  <https://pkg.jenkins.io/debian-stable> binary/ | sudo tee \\
  /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt-get update
sudo apt-get install jenkins
  1. jenkins 다운로드할때 key를 사용해서 설치 할 수 있도록 key를 받아온다.
  2. apt 프로그램을 사용하는데 jenkins는 linux에서 제공하는게 아니라 third party service다. 따라서, repository가 어디있는지 apt에게 알려준다.
  3. jenkins 설치 전 apt-get 을 update하고 설치

Java 설치

sudo apt update
sudo apt install fontconfig openjdk-17-jre
java -version
openjdk version "17.0.8" 2023-07-18
OpenJDK Runtime Environment(build 17.0.8+7-Debian-1deb12u1)
OpenJDK 64-Bit Server VM(build 17.0.8+7-Debian-1deb12u1, mixed mode, sharing)
  • 현재 모든 java 버전이 동작하는게 아니다. 현재는 openjdk-17 지원

설치된 패키지 버전 및 동작 확인

java -version
jenkins --version
sudo systemctl start jenkins
sudo systemctl status jenkins

다양한 소프트웨어 도구들을 연동시켜서(integration) worker node를 control 할 수 있는 CICD Controller.

Jenkins에서 제공하는 웹서비스를 통해서 jenkins를 사용할 수 있어서 편리하다

→ 하나하나 Worker node 들어가서 관리할 필요 x

Local에서 Jenkins 접근

[EC2 instance의 public ip 주소] : 8080 을 웹브라우저에 입력하고 실행하면 unlock jenkins라는 화면이 나온다. 이는 우리가 jenkins 웹에 처음 접근해서 그렇다.

기계가 돌고있는 ip 주소만 알면 8080 포트로 접근해서 Jenkins 웹서비스를 사용할 수 있다.

비밀 번호 확인

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

위 명령어로 나온 비밀번호를 웹에 입력한다.

여기서 install suggested plugins를 클릭

좌측을 클릭하면 다양한 Plugin들을 설치하게 된다.

 

계정명 암호 이름 이메일등을 작성하게 되면 URL 설정하는 화면이 나오는데 EC2 instance를 종료시키기 전까지는 Public IP는 그대로이므로 그대로 진행하면 된다.

 

아래는 Jenkins 웹서비스 화면이다.

Test, build, Containerize, deploy 등의 모든 과정을 job으로 해서 Jenkins에 할당할 수 있다.

이러한 job을 실행시키는걸 Jenkins에서는 build 한다고 한다.

Tools

Maven

code를 compile하고 build하는 도구. 널리 쓰이는 다양한 라이브러리들을 관리하는 도구를 build 도구라고 하는데 maven도 이 중에서 하나. Maven은 java로 작성한 코드를 build하는 도구.

다양한 dependency들을 maven repository가 관리해준다. 따라서, 사용자들은 maven에 뭐가 필요한지 표시만 해주면 된다. 표시를 해주면 maven의 Repository에 가서 가져온다.

Gradle이라는 도구도 java & springboot framework 사용시 자주 사용되는 빌더인데 gradle도 maven repository에서 가져온다.

Jenkins는 Java로 만들어져있다. Jenkins가 Java Framework를 사용하는 프로젝트를 컨트롤하는 소프트웨어로 시작했지만 현재는 확장이 되어 다른 프로그래밍 언어에 대해서도 관리가 가능하다. 따라서, Maven Configuration이 default로 제공된다.

JDK

Worker node에서 다른 버전의 JDK를 사용하는 경우 JDK를 Add해줘야한다. 하지만 우리는 앞서 JDK 17을

설치했으므로 따로 필요가 없다.

Git installation

Name은 본인이 알아서 설정하면 된다.

Github에 source code가 등재되면 github에서 git clone을 해서 CICD flow를 구성해준다.

새로운 item

item은 Jenkins job이다. Job의 종류는 freestyle, pipeline 등 다양하다.

Jenkins도 모든 s/w 도구들을 plugin으로 install 해서 적용 가능하다.

코드 개발부터 테스트, 배포까지 자동적으로 이루어질 수 있게 한다.

github에 새 코드가 들어오면 어떤 기기에서 테스트하게도 할 수 있다.

 

이제 freestyle project를 하나 만들어보자.

이름을 임의로 정하고 OK를 눌러주면 새로운 job이 생성된다.

세부 설정은 이후에 정하고 우선은 다 넘어가고 build step으로 가자

Build Step

우리는 Ubuntu 환경이니까 execute Shell을 설정한다.

pwd
echo "Hello World!"

이후 저장을 누르면 첫번째 job이 생성된다.

이후 좌측 네비게이션 탭에서 지금 빌드를 클릭하자

좌측 하단에 초록색 체크표시가 있다면 제대로 동작하는 것이다.

그리고 #1 #2 #3으로 보이는 링크를 클릭하면 콘솔 출력도 확인할 수 있다.

로그를 확인하면 Building in workspace [경로] 를 확인할 수 있는데 이는 실제 작업이 해당 [경로]에서 이루어진다는 의미이다.

 

Reference Site

https://www.jenkins.io/doc/book/installing/linux/

728x90

SSH란?

SSH는 Secure Shell의 줄임말로, 원격 호스트에 접속하기 위해 사용되는 보안 프로토콜

*Shell(쉘): 명령어와 프로그램을 사용할 때 쓰는 인터페이스로 사용자로부터 명령을 받아 그것을 해석하고 실행

기존 원격 접속은 ‘텔넷(Telnet)’이라는 방식을 사용했는데, 암호화를 제공하지 않기 때문에 보안상 취약했다.

실제로 WireShark같은 패킷 분석 프로그램을 이용하면 누구나 쉽게 원격 접속 과정에서 옮겨지는 비밀번호나 파일 내용 등의 데이터를 탈취할 수 있다. 이러한 보안 문제를 해결하기 위해서 암호화 기술인 SSH가 등장했고 현재 원격 접속을 위해서 필수적이다.

클라우드 환경에 접속하기 위해서는 원격접속이 필수이므로 SSH도 그만큼 많이 사용하게된다.

SSH 작동 원리

SSH를 구성하는 가장 핵심적인 키워드는 ‘KEY(키, 열쇠)’입니다. 사용자(클라이언트)와 서버(호스트)는 각각의 키를 보유하고 있으며, 이 키를 이용해 연결 상대를 인증하고 안전하게 데이터를 주고 받게 된다. 키를 생성하는 방식은 두가지로 ‘대칭키’와 ‘비대칭키(또는 공개 키)’ 방식이다.

비대칭키 방식

https://medium.com/@jamessoun93/ssh%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94-87b58c521d6f

SSH 연결에서는 클라이언트와 서버가 서로를 증명해야하는데 이 시점에서 비대칭키가 사용된다. 서버나 클라이언트가 공개 키와 개인 키를 가지는 key pair를 만든다.

사용자가 키 페어를 생성한 경우 공개 키를 서버에 전송한다. 이때 공개 키는 누구나 가져도 상관이 없다.

서버는 수신한 공개키로 랜덤한 숫자를 생성하고 이 값은 클라이언트가 올바른 개인키를 가지고 있는지 확인하는 용도로 사용된다. 사용자는 개인키로 이 값을 풀고 서버에 전송한다.

서버는 수신한 값을 원래 본인이 생성한 값과 비교해서 두 값이 같으면 인증이 완료된다.

 

대칭키 방식

https://medium.com/@jamessoun93/ssh%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94-87b58c521d6f

서로 클라이언트와 서버라는 사실을 확인했으니 정보를 주고받을 수 있다.

정보를 전송할때 정보 유출을 막기 위해서 대칭키를 이용하여 암호화를 수행한다.

대칭키 방식에서는 비대칭키 방식과 달리 한 개의 키만을 사용한다.

사용자 또는 서버는 하나의 대칭 키를 만들어 서로 공유하고 공유된 대칭 키를 이용해 정보를 암호화하면, 받은 쪽에서 동일한 대칭 키로 암호를 풀어 정보를 습득하게 된다. 대칭키는 정보 교환이 완료되는 대로 폐기하고 접속시마다 새로운 대칭키를 생성해서 사용한다.

Reference

https://library.gabia.com/contents/infrahosting/9002/

728x90

문제 설명

선물을 직접 전하기 힘들 때 카카오톡 선물하기 기능을 이용해 축하 선물을 보낼 수 있습니다. 당신의 친구들이 이번 달까지 선물을 주고받은 기록을 바탕으로 다음 달에 누가 선물을 많이 받을지 예측하려고 합니다.

  • 두 사람이 선물을 주고받은 기록이 있다면, 이번 달까지 두 사람 사이에 더 많은 선물을 준 사람이 다음 달에 선물을 하나 받습니다.
    • 예를 들어 AB에게 선물을 5번 줬고, BA에게 선물을 3번 줬다면 다음 달엔 AB에게 선물을 하나 받습니다.
  • 두 사람이 선물을 주고받은 기록이 하나도 없거나 주고받은 수가 같다면, 선물 지수가 더 큰 사람이 선물 지수가 더 작은 사람에게 선물을 하나 받습니다.
    • 선물 지수는 이번 달까지 자신이 친구들에게 준 선물의 수에서 받은 선물의 수를 뺀 값입니다.
    • 예를 들어 A가 친구들에게 준 선물이 3개고 받은 선물이 10개라면 A의 선물 지수는 -7입니다. B가 친구들에게 준 선물이 3개고 받은 선물이 2개라면 B의 선물 지수는 1입니다. 만약 AB가 선물을 주고받은 적이 없거나 정확히 같은 수로 선물을 주고받았다면, 다음 달엔 BA에게 선물을 하나 받습니다.
    • 만약 두 사람의 선물 지수도 같다면 다음 달에 선물을 주고받지 않습니다.

위에서 설명한 규칙대로 다음 달에 선물을 주고받을 때, 당신은 선물을 가장 많이 받을 친구가 받을 선물의 수를 알고 싶습니다.

친구들의 이름을 담은 1차원 문자열 배열 friends 이번 달까지 친구들이 주고받은 선물 기록을 담은 1차원 문자열 배열 gifts가 매개변수로 주어집니다. 이때, 다음달에 가장 많은 선물을 받는 친구가 받을 선물의 수를 return 하도록 solution 함수를 완성해 주세요.


제한사항

  • 2 ≤ friends의 길이 = 친구들의 수 ≤ 50
    • friends의 원소는 친구의 이름을 의미하는 알파벳 소문자로 이루어진 길이가 10 이하인 문자열입니다.
    • 이름이 같은 친구는 없습니다.
  • 1 ≤ gifts의 길이 ≤ 10,000
    • gifts의 원소는 "A B"형태의 문자열입니다. A는 선물을 준 친구의 이름을 B는 선물을 받은 친구의 이름을 의미하며 공백 하나로 구분됩니다.
    • ABfriends의 원소이며 AB가 같은 이름인 경우는 존재하지 않습니다.

입출력 예

friends gifts result
["muzi", "ryan", "frodo", "neo"] ["muzi frodo", "muzi frodo", "ryan muzi", "ryan muzi", "ryan muzi", "frodo muzi", "frodo ryan", "neo muzi"] 2
["joy", "brad", "alessandro", "conan", "david"] ["alessandro brad", "alessandro joy", "alessandro conan", "david alessandro", "alessandro david"] 4
["a", "b", "c"] ["a b", "b a", "c a", "a c", "a c", "c a"] 0

입출력 예 설명

입출력 예 #1

주고받은 선물과 선물 지수를 표로 나타내면 다음과 같습니다.

↓준 사람 \ 받은 사람→ muzi ryan frodo neo
muzi - 0 2 0
ryan 3 - 0 0
frodo 1 1 - 0
neo 1 0 0 -
이름 준 선물 받은 선물 선물 지수
muzi 2 5 -3
ryan 3 1 2
frodo 2 2 0
neo 1 0 1

muzi는 선물을 더 많이 줬던 frodo에게서 선물을 하나 받습니다.

ryan은 선물을 더 많이 줬던 muzi에게서 선물을 하나 받고, 선물을 주고받지 않았던 neo보다 선물 지수가 커 선물을 하나 받습니다.

frodo는 선물을 더 많이 줬던 ryan에게 선물을 하나 받습니다.

neo는 선물을 더 많이 줬던 muzi에게서 선물을 하나 받고, 선물을 주고받지 않았던 frodo보다 선물 지수가 커 선물을 하나 받습니다.

다음달에 가장 선물을 많이 받는 사람은 ryanneo이고 2개의 선물을 받습니다. 따라서 2를 return 해야 합니다.

입출력 예 #2

주고받은 선물과 선물 지수를 표로 나타내면 다음과 같습니다.

↓준 사람 \ 받은 사람→ joy brad alessandro conan david
joy - 0 0 0 0
brad 0 - 0 0 0
alessandro 1 1 - 1 1
conan 0 0 0 - 0
david 0 0 1 0 -
이름 준 선물 받은 선물 선물 지수
joy 0 1 -1
brad 0 1 -1
alessandro 4 1 3
conan 0 1 -1
david 1 1 0

alessandro가 선물을 더 많이 줬던 joy, brad, conan에게서 선물을 3개 받습니다. 선물을 하나씩 주고받은 david보다 선물 지수가 커 선물을 하나 받습니다.

david는 선물을 주고받지 않았던 joy, brad, conan보다 선물 지수가 커 다음 달에 선물을 3개 받습니다.

joy, brad, conan은 선물을 받지 못합니다.

다음달에 가장 선물을 많이 받는 사람은 alessandro이고 4개의 선물을 받습니다. 따라서 4를 return 해야 합니다.

입출력 예 #3

ab, ac, bc 사이에 서로 선물을 주고받은 수도 같고 세 사람의 선물 지수도 0으로 같아 다음 달엔 아무도 선물을 받지 못합니다. 따라서 0을 return 해야 합니다.

  • 1차 시도

    def solution(friends, gifts):
    current_cnt = {}
    next_cnt = {}
    send_cnt = {}
    receive_cnt = {}
    present_idx = {}
    
    for gift in gifts:
        sender = gift.split()[0]
        receiver = gift.split()[1]
        send_cnt[sender] += 1
        receive_cnt[receiver] += 1
        current_cnt[gift] += 1
    
    for friend in friends:
        present_idx[friend] = send_cnt[friend]-receive_cnt[friend]
    
    for i in len(friends):
        for j in len(friends)-i:
            A = friends[i]
            B = friends[j]
            type_A = str(A) + " " + str(B)
            type_B = str(A) + " " + str(B)
    
            if currend_cnt(type_A) > currend_cnt(type_B):
                next_cnt[A] += 1
            elif currend_cnt(type_A) < currend_cnt(type_B):
                next_cnt[B] += 1
            else:
                if present_idx[A] > present_idx[B]:
                    next_cnt[A] += 1
                elif present_idx[A] < present_idx[B]:
                    next_cnt[B] += 1
    
    answer = max(next_cnt.values())
    return answer
  • 2차 시도(올클)

      import numpy as np
    
      def solution(friends, gifts):
          lf = len(friends)
          table_gift = np.zeros((lf,lf))
          table_idx = np.zeros(lf)
          find_max = np.zeros(lf)
    
          #선물 주고 받은 표 데이터
          for gift in gifts:
              i = friends.index(gift.split()[0])
              j = friends.index(gift.split()[1])
              table_gift[i][j] += 1
              #선물 지수 계산
              table_idx[i] += 1
              table_idx[j] -= 1
    
          for i in range(lf):
              for j in range(i+1,lf):
                  if table_gift[i][j] > table_gift[j][i]:
                      find_max[i] += 1
                  elif table_gift[i][j] < table_gift[j][i]:
                      find_max[j] += 1
                  else:
                      if table_idx[i] > table_idx[j]:
                          find_max[i] += 1 
                      elif table_idx[i] < table_idx[j]:
                          find_max[j] += 1 
          answer = max(find_max)
          return answer
      테스트 1 〉    통과 (0.08ms, 28.3MB)
      테스트 2 〉    통과 (0.13ms, 28.2MB)
      테스트 3 〉    통과 (0.23ms, 28.6MB)
      테스트 4 〉    통과 (0.17ms, 27.9MB)
      테스트 5 〉    통과 (3.36ms, 28.7MB)
      테스트 6 〉    통과 (0.42ms, 28.3MB)
      테스트 7 〉    통과 (2.28ms, 28.1MB)
      테스트 8 〉    통과 (2.02ms, 28.5MB)
      테스트 9 〉    통과 (12.59ms, 28.7MB)
      테스트 10 〉    통과 (11.59ms, 28.5MB)
      테스트 11 〉    통과 (12.13ms, 28.5MB)
      테스트 12 〉    통과 (8.71ms, 28.4MB)
      테스트 13 〉    통과 (22.60ms, 28.9MB)
      테스트 14 〉    통과 (21.58ms, 28.7MB)
      테스트 15 〉    통과 (22.93ms, 28.6MB)
      테스트 16 〉    통과 (23.13ms, 28.7MB)
      테스트 17 〉    통과 (0.18ms, 28.2MB)
      테스트 18 〉    통과 (13.12ms, 28.6MB)
      테스트 19 〉    통과 (24.97ms, 28.6MB)
      테스트 20 〉    통과 (9.72ms, 28.3MB)
  • 테이블 생성

  • 3차 시도(올클) - for 문으로 리스트 초기화

    def solution(friends, gifts):
    length = len(friends)
    table_gift = [[0 for _ in range(length)] for _ in range(length)]
    table_idx = [0 for _ in range(length)]
    find_max = [0 for _ in range(length)]
    
    #선물 주고 받은 표 데이터
    for gift in gifts:
        i = friends.index(gift.split()[0])
        j = friends.index(gift.split()[1])
        table_gift[i][j] += 1
        #선물 지수 계산
        table_idx[i] += 1
        table_idx[j] -= 1
    
    for i in range(length):
        for j in range(i+1,length):
            if table_gift[i][j] > table_gift[j][i]:
                find_max[i] += 1
            elif table_gift[i][j] < table_gift[j][i]:
                find_max[j] += 1
            else:
                if table_idx[i] > table_idx[j]:
                    find_max[i] += 1 
                elif table_idx[i] < table_idx[j]:
                    find_max[j] += 1 
    answer = max(find_max)
    return answer
      테스트 1 〉    통과 (0.04ms, 10.2MB)
      테스트 2 〉    통과 (0.05ms, 10.2MB)
      테스트 3 〉    통과 (0.10ms, 10.3MB)
      테스트 4 〉    통과 (0.07ms, 10.1MB)
      테스트 5 〉    통과 (1.46ms, 10.2MB)
      테스트 6 〉    통과 (0.18ms, 10.2MB)
      테스트 7 〉    통과 (1.01ms, 10.1MB)
      테스트 8 〉    통과 (0.95ms, 10.2MB)
      테스트 9 〉    통과 (4.41ms, 10.5MB)
      테스트 10 〉    통과 (5.47ms, 10.4MB)
      테스트 11 〉    통과 (5.47ms, 10.5MB)
      테스트 12 〉    통과 (3.90ms, 10.5MB)
      테스트 13 〉    통과 (12.97ms, 10.7MB)
      테스트 14 〉    통과 (15.82ms, 10.6MB)
      테스트 15 〉    통과 (12.88ms, 10.6MB)
      테스트 16 〉    통과 (14.04ms, 10.8MB)
      테스트 17 〉    통과 (0.08ms, 10.1MB)
      테스트 18 〉    통과 (4.50ms, 10.5MB)
      테스트 19 〉    통과 (13.11ms, 10.4MB)
      테스트 20 〉    통과 (2.65ms, 10.3MB)

    사용 기술

  • 선형 탐색

  • 2차원 배열 데이터베이스 구현

Trouble Shooting

  • dict 타입이 hash 기반이라 더 빠르다고 dict를 쓰려고 억지를 부리다 시간이 오래걸렸다.
    2차원 배열도 충분히 좋으니까 쉬운 문제에서는 2차원 배열로 구현하자

Main Point

  • numpy로 배열 초기화하는거보다 2중 for 문이 더 빠르다
  • 조건 따질때는 2차원 배열도 좋은 옵션이다
  • list의 .index(값) 메서드를 사용하면 index(몇번째 원소인지)를 알아낼 수 있다.
728x90

iterm2를 새로 설치하게 되면서 기존 디폴트 쉘이 bash에서 zsh로 변경되었다. 근데 쉘이 변경되면서 conda 명령어를 인식을 못해서
왜그런가 했더니 환경변수를 설정해주지 않아서 그랬던 것이었다.
conda 설치 경로를 확인하려고 우선 bash로 전환하고 아래 명령어를 통해 conda 경로를 확인했다.

#디폴트 쉘 bash로 설정
chsh -s /bin/bash
#디폴트 쉘 zsh로 설정
chsh -s /bin/zsh
#conda 경로 확인
which conda

conda 경로 확인하면 zshrc 파일을 열어서 맨 아래 코드를 추가한다

#환경변수 파일 즉,zshrc 파일을 열어야 한다.
vim ~/.zshrc

이때 /path/to/anaconda 부분을 본인 conda 경로로 바꿔준다.

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/path/to/anaconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
    eval "$__conda_setup"
else
    if [ -f "/path/to/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/path/to/anaconda3/etc/profile.d/conda.sh"
    else
        export PATH="/path/to/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda initialize <<<

이후 vim 종료하고 아래 코드로 환경변수 변경 사항을 반영한다.

source ~/.zhsrc

그럼 끝~

728x90

이미 초기화된 원격의 저장소를 복제해와서 개발하는 경우, 복제 작업을 Git에서는 클론(clone)이라고 부르며 git clone서브 명령어로 구현되어있습니다. 이번 글에서는 git clone명령어의 사용법에 대해서 자세히 소개합니다.

 

1. 리포지토리 생성

혼자서 개발하는 경우에는 로컬에서 Git 저장소를 초기화해서 사용하면 됩니다만, 협업을 하는 경우나 인터넷에 소스 코드를 공개하는 경우 GitHub에 저장소를 만들고 이 저장소를 클론해서 작업하는 방식을 주로 사용합니다.

2. Git 저장소의 주소 파악하기

클론을 하려면 Git 저장소의 주소를 알아야합니다. 화면에서 Code 버튼을 클릭하면 Git 저장소 주소가 나타납니다. Git 저장소의 주소는 HTTPS와 SSH 방식으로 제공되며 다음과 같은 형식을 따릅니다. (메뉴에서 알 수 있지만, ZIP 압축 파일로 다운로드 받을 수도 있습니다.)

HTTPS와 SSH 형식의 GitHub 저장소 주소는 아래와 같습니다.

# HTTPS 형식
<https://github.com/[USERNAME]/[REPOSITORY_NAME].git>

# SSH 형식
git@github.com:[USERNAME]/[REPOSITORY_NAME].git

[USERNAME]은 GitHub 사용자 이름으로, [REPOSITORY_NAME]은 저장소를 생성할 때 지정한 저장소 이름이 됩니다.

3. git clone의 명령어 형식

git clone [REPO_URL] [DIR]

[REPO_URL]에는 클론해올 저장소의 주소를 지정해줍니다. [DIR]인자는 저장소를 로컬에 복제할 위치를 지정합니다. [DIR]생략 가능하며, 특별한 이유가 없다면 보통 생략합니다.

4. git clone 실행하기

우선 clone을 할 디렉터리로 이동을 한후 다음 명령어를 실행한다.

git clone <https://github.com/BangProx/webstudy-homework-BangProx.git>

git repository가 성공적으로 클론된 것을 확인할 수 있다!

'개발 > git 사용법' 카테고리의 다른 글

(3) git commit 실습해보기  (0) 2024.03.13
(2) git 기초 실습해보기  (0) 2024.03.13
(1) git이란?  (0) 2024.03.13
728x90

📌 파일들을 수정하다 마음에 들면 staging area에 옮겨 놓고 드디어 commit 혹은 version을 만들 준비가 되었습니다.

1. commit 실습

  • commit 사용해보기

version을 만들때는 commit이라는 명령어를 사용할 수 있는데, staging area에 있는
변경 사항을 git repository에 옮겨주는 역할을 한다. 아무런 옵션 없이 이용하게 되면
기본적인 template이 나오는데 보통은 Title을 작성하고 좀더 자세한 Description을 작성한 다음에 파일을 닫으면 위와 같이 나온다.


첫째 줄을 보면 main branch에 hash code의 제일 앞부분만 나온다.
hash code 아이디와 Title이 표기된다. 3가지의 파일이 변경되었고 3가지 다 처음으로
만들어진 파일이란 것을 확인할 수 있다.

  • git history를 확인해보자
git log

commit 과 전체적인 hashcode가 나오고 누가 언제 했는지 확인할 수 있다.
그리고 Title 과 Description 이 나오는 것을 확인할 수 있다.

  • 위와 같은 방식으로 git commit을 바로하는 경우는 거의 없고 다른 방식을 한다
echo add >> c.txt#c.txt를 수정한다
git status -s #c.txt의 상태 확인
git add. #전부다 추가
git commit -m "second commit"
git log

git commit -m 뒤에 메시지를 추가해서 간단하게 commit할 수 있다
동일하게 log 를 확인해보면 두번째 commit이 이뤄진것을 확인할 수 있다.

  • working directory에서 add를 사용하지 않고 전부 다 바로 commit을 해보자.
echo add >> c.txt #c.txt에 수정사항을 만들어서 working directory에 존재
git commit -am "third commit"
git status -s #git status가 깔끔해졌다

staging area와 working directory의 모든 파일들이 commit된 것을
확인해 볼 수 있다.

2. commit 팁

git directory에 있는 파일들은 사실 history에 창고다. 작업들을 버전별로 나눠서
관리할 수 있는 유용한 창고이다. 따라서 전체 어플리케이션을 만들어서 저장하면
의미가 없다. 어플리케이션을 세분화해서 기능별로 작은 단위로 만들어 나가는게
중요하다. 작은 단위로 나눠서 history에 저장하는게 중요하다.


의미있는 이름을 지정해서 저장하는게 중요하다.
예를 들어, 프로젝트를 초기화하는 commit 하나, login 서비스 모듈을 만들어서 commit하는 식으로 작은 단위로 의미있게 history를 보면 작업한 내용을 알아볼 수 있게 저장하는게 중요하다.


보통 commit의 메시지는 현재형으로 동사로 만들어진다. init, add, fix 등
commit을 할때 내가 crushing 을 고쳤다고 하면 정말 고친 내용만 포함한 commit을 만들어야지 다른 버그들 고친 것도 commit을 하면 코드를 리뷰할때도 혼동이 오지만
history를 볼때도 혼동이 온다. 따라서 commit 메시지에 맞게 해당 내용만 commit하는 것이 중요하다.

'개발 > git 사용법' 카테고리의 다른 글

(4) git clone 실습해보기  (0) 2024.03.13
(2) git 기초 실습해보기  (0) 2024.03.13
(1) git이란?  (0) 2024.03.13
728x90

1. 파일 생성하기

  • hello world 라는 문자열을 a.txt 파일에 저장하는 명령
echo hello world! > a.txt
#그냥 파일 위치를 열어서 텍스트 파일을 만들어도 된다.
open .

터미널에서는 방향키 위 버튼을 누르면 이전에 작성한 명령어를 다시 활용할 수 있다. 동일한 과정으로 파일 3개를 생성하면 된다. (파일명은 a, b, c.txt)

2. git 상태 확인하기

git status

현재 working directory에 a.txt, b.txt. c.txt가 untracked된 상태로 존재한다.

3. staging area로 파일 이동

  • 커밋할 준비가 완료 됐다고 파악하면 add 명령어를 이용해서 파일들을

    staging area로 이동시킨다. 그럼 아래의 이미지와 같이 바뀐다.

git add a.txt

현재 staging area에 a.txt가 존재하고, b.txt 와 c.txt는 아직 working directory에
untracked 상태로 존재한다

  • 나머지 파일들도 add 해준다.
    #1번 방법
    git add b.txt c.txt
    

#2번 방법
git add *.txt #존재하는 모든 txt파일을 add

> 이제 a, b, c 파일이 모두 `commit`할 준비가 되었다.

- 여기서 새로운 문자열 ellie를 a.txt 파일에 추가하게 되면 다시 git status를 확인해보자.

> 총 3가지의 파일은 commit할 준비가 되었다. 하지만 a.txt 파일이 tracked된 상태이고 modified된 것을 확인할 수 있다.

- 다시 a.txt 를 `add` 하고 확인해보자.
> a, b, c가 staging area로 옮겨진 것을 확인할 수 있다. 
또한, 위의 두번째 줄을 통해서 git rm —cached 를 이용해서 staging area에서 
working directory로 옮겨갈 수 있다는걸 확인할 수 있다.

- `git rm —cached`를 이용해서 모든 파일을 staging area에서 제거해보자.

```powershell
#*는 모든 파일을 의미
git rm --cached *

a, b, c 파일들이 untracked 상태로 돌아간 것을 확인할 수 있다.

  • 마지막으로 모든 파일을 staging area로 옮긴후 a.txt를 삭제해보자.
git add *
git status    # 한번 상태를 확인해본다.
rm a.txt      # a.txt 삭제
ls            # 디렉토리에 a.txt가 없는 것을 확인한다.
git add *
git status

a.txt를 제거하고 git status 를 확인하면 삭제된 a.txt는 디렉토리에 없었기 때문에
staging area에 추가되지 않은 것을 확인할 수 있다.

  • git add . 을 실행해보자
git add .
git status

모든 파일들을 포함해서 git staging area에 추가되는 것을 확인할 수 있다.

'개발 > git 사용법' 카테고리의 다른 글

(4) git clone 실습해보기  (0) 2024.03.13
(3) git commit 실습해보기  (0) 2024.03.13
(1) git이란?  (0) 2024.03.13

+ Recent posts