<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>samdaso-o.log</title>
        <link>https://velog.io/</link>
        <description>ㅎㅅㅎ</description>
        <lastBuildDate>Thu, 03 Mar 2022 08:49:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>samdaso-o.log</title>
            <url>https://images.velog.io/images/samdaso-o/profile/7b10aa10-9caa-4002-a2d0-d288ec6439dd/common.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. samdaso-o.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/samdaso-o" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Docker 자원 할당?]]></title>
            <link>https://velog.io/@samdaso-o/Docker-%EC%9E%90%EC%9B%90-%ED%95%A0%EB%8B%B9</link>
            <guid>https://velog.io/@samdaso-o/Docker-%EC%9E%90%EC%9B%90-%ED%95%A0%EB%8B%B9</guid>
            <pubDate>Thu, 03 Mar 2022 08:49:33 GMT</pubDate>
            <description><![CDATA[<h2 id="docker-컨테이너-자원-할당">Docker 컨테이너 자원 할당?</h2>
<h3 id="글을-적게-된-계기">글을 적게 된 계기</h3>
<p>근래에 스레드 및 세마포어라는 개념에 관심을 갖고 학습을 했다. 그러면서 자연스럽게 자원 할당이라는 개념에 관심을 가지게 되었고, 본 글쓴이가 자주 사용하면서 서버와 직결되는 docker 자원할당에 의문점을 갖게 되었다.</p>
<p>의문점을 갖고 학습한 내용을 기술할려고 한다.</p>
<h3 id="docker">Docker</h3>
<p>일단 docker는 기본적으로 옵션을 따로 지정하지 않고 실행을 하면, 호스트의 자원을 제한 없이 사용할 수 있게 설정이 된다.</p>
<p>그저 개인 프로젝트나 테스트라면 문제가 없겠지만, 제품단계의 프로그램이라면 문제가 발생할 것이다. 
그래서 컨테이너에 자원 제한을 걸 수가 있는데, 컨테이너가 실행 또는 실행중일 때 run, create, update와 같은 명령어들로 컨테이너의 자원 할당량을 설정 및 조정 가능하다.</p>
<h4 id="1-현재까지-사용한-컨테이너-자원제한-확인-방법">1. 현재까지 사용한 컨테이너 자원제한 확인 방법</h4>
<p>일단 기본적으로 자원할당을 하기전 확인부터 할 수 있어야 한다고 생각한다.
아래의 명령어로 컨테이너의 상세 정보 및 자원할당량을 확인할 수 있다.</p>
<blockquote>
<p>docker inspect <container_name></p>
</blockquote>
<p>명령어를 입력하게 된다면, 컨테이너의 기본 정보(ex. id, state등등) 및 네트워크 정보까지 출력된다.</p>
<p>여기서 우리가 주목해야될 부분은 memory 및 cpu, block I/O 부분이다.
만약 따로 설정을 하지 않고 바로 inspect 명령어를 입력했다면, 대부분의 기본값이 0 일 것이다. 
0 인 이유는 그냥 호스트 서버의 자원을 전부 사용하겠다라는 뜻이다. </p>
<h4 id="2-새로-실행할-경우-memory-옵션-제한하기">2. 새로 실행할 경우 Memory 옵션 제한하기</h4>
<p>간단하다.
docker run 명령어에 --memory 옵션만 붙히면 된다.</p>
<blockquote>
<p>docker run -d <br>--memory=&quot;1g&quot; \ 
--name memory_1g \ 
test_image:1.0.0</p>
</blockquote>
<p>참고로 최소 메모리 할당량은 4MB이며, m은 MB를, g는 GB를 뜻한다. 컨테이너에 할당된 메모리가 초과되면 컨테이너가 종료되니 메모리를 적절히 할당해야한다.</p>
<p>또한 swap도 적용가능하다. (메모리가 부족할 때 하드디스크의 일부를 활용해 작업을 계속 진행하게 도와주는 영역)</p>
<blockquote>
<p>docker run -d <br>--name memory_1g <br>--memory=&quot;1g&quot; \ 
--memory-swap=500m \ 
test_image:1.0.0</p>
</blockquote>
<h4 id="3-cpu-제한">3. cpu 제한</h4>
<p>--cpu-shares 옵션
위의 옵션은 cpu 코어의 갯수를 할당해서 정하는 것이 아니라, 컨테이너에 가중치를 정해 해당 컨테이너가 호스트의 존재하는 cpu를 어느 정도의 비중까지 나눠 쓸것인지 명시할 수 있다.</p>
<blockquote>
<p>docker run -d <br>--name cpu_share1 <br>--cpu-shares 1024 \ 
test_image:1.0.0</p>
</blockquote>
<p>별다른 설정을 하지 않았다면 1024는 할당량 1을 뜻한다.</p>
<p>--cpuset-cpu 옵션
컨테이너가 특정 cpu만 사용할 수 있게 설정하는 옵션이다.</p>
<blockquote>
<p>docker run -d <br>--name cpuset1 <br>--cpuset-cpus=2 \ 
test_image:1.0.0</p>
</blockquote>
<p>--cpus
cpu의 갯수를 직접 지정할 수 있는 명령어이다.</p>
<blockquote>
<p>docker run -d <br>--name cpus1 <br>--cpus=0.5 \ 
test_image:1.0.0</p>
</blockquote>
<h4 id="block-io-제한">Block I/O 제한</h4>
<p>이것 또한 컨테이너를 생성할때 옵션을 설정하지 않으면 내부에서 파일을 읽고 쓰는 대역폭 제한이 설정되지 않는다.</p>
<p>그래서 --device-write-bps, --device-read-bps, --device-write-iops, --device-read-iops옵션을 지정해 블록 입출력을 제한할 수 있다.</p>
<p>--device-write-bps, --device-read-bps는 각기 쓰고 읽는 작업의 초당 제한을 설정하며 kb, mb, gb 단위로 제한할 수 있다.</p>
<h3 id="마무리">마무리</h3>
<p>나는 자원할당이 필요한 이유가 적절한 자원할당으로 더 나은 성능을 클라이언트에게 제공하는 것이라고 생각을 한다.</p>
<p>로깅이나 서버 스펙업을 진행하는 이유도 최종적으로는 클라이언트에게 좀 더 빠르고 나은 성능을 제공하기 위함이라고 생각이 드는데, 이러한 점들을 생각해보면 자원할당은 선택적인 사항이 아니라 필수적인 사항이라는 생각이 든다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linux 초심 찾기...]]></title>
            <link>https://velog.io/@samdaso-o/Linux-%EC%B4%88%EC%8B%AC-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@samdaso-o/Linux-%EC%B4%88%EC%8B%AC-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Fri, 18 Feb 2022 06:00:32 GMT</pubDate>
            <description><![CDATA[<h2 id="적게-된-계기">적게 된 계기</h2>
<p>분명 머리는 이해하고 있는 개념인데 다른 사람에게 설명을 할 때에는 입에서 맴돌고 설명하지 못하는 경우가 종종 생기곤 했다. 정리가 되지 않은 개념이라고 생각되어 확실하게 정리하고자 적게 되었다.</p>
<h2 id="리눅스-권한-체계">리눅스 권한 체계</h2>
<h3 id="rwx">r..w..x..?</h3>
<ul>
<li>read(r) : 읽기 권한</li>
<li>write(w) : 쓰기 및 수정 권한</li>
<li>execute(x) : 실행 권한</li>
</ul>
<p>리눅스에서 파일 권한을 확인하고자 한다면 ll 또는 ls -l 명령어를 치면 된다.
위 명령어를 치게 된다면 아래와 같은 화면이 출력되게 되는데 하나씩 알아보도록 하자.
<img src="https://images.velog.io/images/samdaso-o/post/298cb28c-418f-40d3-a3a0-0cedf4a8aeb8/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-18%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.31.28.png" alt=""></p>
<p>맨 앞쪽의 10개의 문자들은 권한 구성을 나타내는 것이다. 10개 문자는 4개의 그룹으로 나뉜다.</p>
<h4 id="1번째-문자">1번째 문자</h4>
<p>1번째 문자는 파일 또는 폴더/디렉토리 및 링크를 표시하는 문자이다.</p>
<ul>
<li><ul>
<li>: 파일이라는 뜻</li>
</ul>
</li>
<li><p>d : 폴더/디렉토리라는 뜻</p>
</li>
<li><p>l : 링크라는 뜻</p>
<h4 id="2-4번째-문자">2-4번째 문자</h4>
<p>파일 주인의 읽기, 쓰기, 실행 권한을 표시하는 것이다.
위 사진을 예시로 들자면 첫번째 경로 권한의 주인은 root이고 &#39;rwx&#39;가 전부 있으므로 모든 권한을 사용할 수 있다는 뜻이다.</p>
<h4 id="5-7번째-문자">5-7번째 문자</h4>
<p>파일 주인이 속한 그룹의 읽기, 쓰기, 실행 군한 표시</p>
<h4 id="8-10번째-문자">8-10번째 문자</h4>
<p>그 외 유저들 읽기, 쓰기, 실행 권한 표시</p>
<h3 id="그룹">그룹?</h3>
<h4 id="그룹확인">그룹확인</h4>
<p>그룹을 확인하고 싶다면 /etc/group 파일에서 확인 가능하다.</p>
<blockquote>
<p>tail /etc/group</p>
</blockquote>
<p>결과값은 GID(group id)오름차순으로 설정되어있다. 그룹은 기본적으로 사용자를 생성할때 자동으로 생성된다.</p>
<h4 id="유저확인">유저확인</h4>
<p>한명의 유저의 그룹정보를 확인하고 싶다면 id 명령어를 사용하면 된다.</p>
<blockquote>
<p>id test_user1</p>
</blockquote>
<p>위의 명령어를 사용한다면 test_user1의 UID(user id), GID(group id), 그리고 속해있는 그룹에 대한 정보가 출력된것을 볼 수 있다.</p>
<h4 id="그룹생성">그룹생성</h4>
<p>그룹 생성 명령어는 groupadd 다.
원한다면 -g 옵션으로 GID 그룹ID를 직접 지정도 가능하다.</p>
<blockquote>
<p>groupadd -g 555 test_group</p>
</blockquote>
<p>그룹 id를 지정해서 생성 후 다음 그룹 생성 시부터는 기존 오름차순으로 생성되던 id가 아닌 가장 큰 숫자를 기준으로 하나씩 증가되며 생성된다.</p>
<h4 id="그룹-유저-추가">그룹 유저 추가</h4>
<p>그룹에 유저를 추가하는 명령어는 usermod 명령어이다. 그리고 -G 옵션으로 추가할 그룹명과 유저명을 입력하면 된다.</p>
<blockquote>
<p>usermod -G test_group test_user1</p>
</blockquote>
<p>참고로 한 유저는 여러 그룹에 포함이 가능하다.(max 3개?) 하지만 그러기 위해서는 /etc/group 파일로 가서 명령어가 아닌 직접 수정이 필요하다.
vim edit를 이용해 편집하면 간단하다. 기존의 형식에 맞춰 작성하고 저장하면 된다.</p>
<h4 id="그룹-삭제">그룹 삭제</h4>
<p>그룹 삭제는 groupdel이라는 명령어를 사용한다.</p>
<blockquote>
<p>groupdel test_group</p>
</blockquote>
<p>만약 삭제하고자 하는 그룹에 속한 유저중에서 그 그룹이 기본 그룹으로 설정되어있는 유저가 있다면, 그 그룹은 삭제되지 않는다는 점 숙지하길 바란다.
만약 그 유저의 기본 그룹을 변경하고 싶다면 usermod 명령어로 변경 후 삭제 작업을 진행하면 된다.</p>
</li>
</ul>
<h3 id="권한-변경">권한 변경</h3>
<blockquote>
<p>chomd [변경하고자 하는 권한 값] [파일 또는 폴더/디렉토리]</p>
</blockquote>
<p> 권한 변경은 chmod(change mode) 명령어를 사용한다.
 chmod는 4개의 그룹중 첫번째 그룹을 제외한 나머지를 지정해주어야한다. 나머지 3개의 그룹을 숫자를 이용해 번경을 해주어야 하는데, 그 숫자는 r, w, x를 전부 더한 값이다.</p>
<ul>
<li><p>r = 4</p>
</li>
<li><p>w = 2</p>
</li>
<li><p>x = 1
예시로 그 그룹에 모든 권한을 부여하고 싶다면 r, w, x를 전부 더한 값인 7을 쓰면된다.</p>
<h3 id="파일-소유권-변경">파일 소유권 변경</h3>
<p>소유권 변경은 root 유저만 가능하므로 root로 login 한 후 진행하길 바란다.</p>
<blockquote>
<p>chown [소유권자]:[그룹 식별자] [소유권을 변경하고 싶은 파일명 또는 디렉토리명]</p>
</blockquote>
<p>위의 사진을 예시로 설명하겠다.
만약 .bash_history 파일을 root유저의 소유로 변경하고 그룹 aaa로 변경하고 싶다면 아래의 명령어로 입력하면 된다.</p>
<blockquote>
<p>chown root:aaa .bash_history</p>
</blockquote>
<p>아 참고로 디렉토리의 소유권 변경은 위의 명령어로 진행할 시 현재 디렉토리만 소유권이 변경되고, 하위의 디렉토리들은 변경이되지 않는다.
만약 하위 디렉토리까지 같이 변경하고 싶다면 아래의 형식의 명령어를 사용하면 된다.</p>
<blockquote>
<p>chown root:aaa /etc/test</p>
</blockquote>
</li>
</ul>
<h3 id="리눅스-파일-찾기">리눅스 파일 찾기</h3>
<blockquote>
<p>find [경로] -name [파일명]</p>
</blockquote>
<p>최상단에서 찾고 싶다면 경로를 /로 지정하여 검색하길 바란다.
파일의 타입을 구별해서 검색하고 싶다면 위의 명령어에 마지막으로 -type f 옵션을 추가하면 파일만 찾아지고, -type d 옵션을 추가하면 디렉토리만 찾아진다.</p>
<p>실행 파일만 찾고 싶다면, 아래의 명령어를 사용하면 된다.</p>
<blockquote>
<p>which [파일명]</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cloudwatch... docker_logs]]></title>
            <link>https://velog.io/@samdaso-o/Cloudwatch...-dockerlogs</link>
            <guid>https://velog.io/@samdaso-o/Cloudwatch...-dockerlogs</guid>
            <pubDate>Wed, 09 Feb 2022 07:21:44 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/samdaso-o/post/874052b3-9047-4e35-93ff-dabf1ca4e347/%E3%85%81%E3%84%B4%E3%85%87%E3%84%B9.jpeg" alt="">
그냥 의식의 흐름대로 정리할 예정..^^</p>
<h2 id="사용하게-된-계기">사용하게 된 계기</h2>
<p>도커의 로그를 외부로 보내는 작업을 진행하고 싶었다.
Docker에서 제공하는  fluentd 이용해서 s3로 던지는 작업이라든지 여러가지 방법이 있었지만, 이미 기존에 cloudwatch를 사용중이였기에 docker에서 awslogs plugin을 사용해 로그를 cloudwatch로 바로 던지는 방법을 사용했당ㅇㅇㅇ</p>
<h2 id="방법쓰">방법쓰..</h2>
<ol>
<li>Cloudwatch 로그 그룹 및 로그 스트림 생성..</li>
</ol>
<ul>
<li>aws cloudwatch로 이동해 로그 그룹 및 스트림 생성할 것 (로그를 받을 공간을 생성하기 위함이라고 이해하면 될듯?)
생성과정에 키를 넣거나 어려운 작업이 존재하지 않으므로 생성과정 설명하지 않겠다!</li>
</ul>
<ol start="2">
<li><p>그리고 IAM에 가서 해당 EC2에서 사용중인 역할에 &quot;CloudWatchLogsFullAccess&quot; 추가할것</p>
</li>
<li><p>그리고 docker-compose file 에 원하는 컨테이너에 스크립트를 기입할것
<img src="https://images.velog.io/images/samdaso-o/post/4f6bb78c-6b2e-4484-855b-a4678b07306e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-09%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.15.49.png" alt=""></p>
</li>
</ol>
<p>음 만약 단일 도커파일로 실행중이라면 아래의 명령어를 이용해도 될듯?</p>
<blockquote>
<p>docker service update --log-driver awslogs --log-opt awslogs-group=&quot;아까 생성한 로그 그룹명&quot; --log-opt awslogs-region=&quot;EC2 리전쓰&quot; --log-opt awslogs-stream=&quot;아까 생성한 로그 스트림명&quot; ${container_name}</p>
</blockquote>
<p>작업이 완료되면 다시 aws cloudwatch에서 생성해놨던 로그 그룹 &amp; 스트림으로 들어가보면 아래와 같이 로그들이 나오는걸 확인할 수 있다.
<img src="https://images.velog.io/images/samdaso-o/post/1f5bac4e-c2ca-4e10-9198-31fc6ee0e745/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-02-09%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.19.57.png" alt="">
(보안을 위해 나머지는 못보여줘.. ELB Health check나 보고가...)</p>
<p>즐거운 개발 ㅎㅎ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Docker image 종속 하위 이미지 지우는 법!]]></title>
            <link>https://velog.io/@samdaso-o/Docker-image-%EC%A2%85%EC%86%8D-%ED%95%98%EC%9C%84-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%A7%80%EC%9A%B0%EB%8A%94-%EB%B2%95</link>
            <guid>https://velog.io/@samdaso-o/Docker-image-%EC%A2%85%EC%86%8D-%ED%95%98%EC%9C%84-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%A7%80%EC%9A%B0%EB%8A%94-%EB%B2%95</guid>
            <pubDate>Tue, 11 Jan 2022 01:56:14 GMT</pubDate>
            <description><![CDATA[<h2 id="종속성부모와-자식">종속성?(부모와 자식..)</h2>
<p>가끔식 서로 종속성을 가지고 있는 docker images들이 존재한다.
하지만 docker images 명령어로도 가끔 확인 불가능한 하위 image들이 존재한다.
그럴 경우 docker images 명령어로 확인되는 부모 image를 삭제할 수 없는 경우가 발생하게 되는데 그때 사용할 수 있는 방법을 알려주겠다.</p>
<h3 id="나와라-자식들아">나와라 자식들아..</h3>
<p>일단 본인은 우분투 20.04환경이라는 것을 알린다.</p>
<blockquote>
<p>image_id=1111111111111 {지우고자 하는 image_id값}</p>
</blockquote>
<blockquote>
<p>docker images -a -q --filter since=$image_id |
xargs docker inspect --format=&#39;{{.Id}} {{.Parent}}&#39;</p>
</blockquote>
<p><img src="https://images.velog.io/images/samdaso-o/post/78808668-9535-4849-b71c-d70a0165d0ba/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-01-11%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.50.23.png" alt=""></p>
<p>그럼 위의 사진과 같이 하위에 종속되어 있는 이미지들이 나온다.
그중 첫번째 image_id를 docker rmi 명령어로 삭제한다.</p>
<p>그 뒤 부모 image를 삭제하면 삭제가 가능할 것이다.</p>
<p>본인은 하위에 image들을 전부 삭제하여 될 것이라는 추측에 첫번째 삭제 후 두번째도 삭제할려고 rmi 명령어를 입력했지만 존재하지 않는다는 응답을 받았다.
(내 예상은 하위에 종속되어있는 이미지끼리 또 관계가 있어서 같이 삭제되지 않았을까라는 추측을 하고 있다.)
만약 첫번째 이미지 삭제 후 부모 이미지가 삭제가 되지 않을 경우, 하위 Image로 출력된 image_id 값들을 전부 삭제하길 바란다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Jenkins 비밀번호 분실?]]></title>
            <link>https://velog.io/@samdaso-o/Jenkins-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EB%B6%84%EC%8B%A4</link>
            <guid>https://velog.io/@samdaso-o/Jenkins-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EB%B6%84%EC%8B%A4</guid>
            <pubDate>Fri, 24 Dec 2021 01:48:42 GMT</pubDate>
            <description><![CDATA[<p>jenkins CI/CD 블로깅을 아직까지 적지 않았다...(죄성함돠..)
집에 가면 유튜브가 얼마나 재밌던지...
이번 주말에 jenkins 자동배포 블로깅 꼭 마무리하도록 하겠다..!</p>
<p><img src="https://images.velog.io/images/samdaso-o/post/a6986315-a046-4856-a571-fd2dd035c9a0/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-24%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.19.27.png" alt=""></p>
<h2 id="jenkins-비밀번호-분실">jenkins 비밀번호 분실?</h2>
<p>처음에 든 생각은 망했다...였다. 싹 밀고 처음부터 다시 시작해야되는건가..? 라는 생각도 들고 일주일간 고생했던 기억이 주마등처럼 지나쳐갔다.</p>
<p>다시 정신을 부여잡고 하늘같은 구글님에게 찾아갔다.
<img src="https://images.velog.io/images/samdaso-o/post/c7f7e731-18ba-4208-8e6a-d2b1ff962c30/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-24%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.41.10.png" alt=""></p>
<p>다행히 간절한 내 마음을 알아주신 구글님께서 해답을 주셨다.
구글링으로 찾은 방법은 jenkins의 설정파일에서 로그인 부분을 접속하지 않고 통과하도록 설정하는 방법이였다.</p>
<ol>
<li><p>jenkins의 config 파일에 접속한다.</p>
<blockquote>
<p>sudo vi /var/lib/jenkins/config.xml</p>
</blockquote>
</li>
<li><p>jenkins config 파일내의 </p>
<blockquote>
<p>&lt; useSecurity&gt; True &lt; /useSecurity&gt;</p>
</blockquote>
<p>위 항목을 찾아, true를 false로 변경한다.</p>
</li>
<li><p>그리고 마지막으로 jenkins을 재시작한다.</p>
</li>
</ol>
<p>그렇게 jenkins에 다시 접속한다면 로그인 화면이 아니라 대시보드 화면이 바로 출력될 것이다. 대시보드에서 비밀번호를 재설정하고 다시 위의 과정을 역으로 반복해서 사용할 것을 추천한다. (너의 보안은 중요하니까..ㅎ)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Jenkins + Github (1 / 3)]]></title>
            <link>https://velog.io/@samdaso-o/Jenkins-Github-1-3</link>
            <guid>https://velog.io/@samdaso-o/Jenkins-Github-1-3</guid>
            <pubDate>Tue, 14 Dec 2021 13:09:13 GMT</pubDate>
            <description><![CDATA[<p>어느덧 입사한지 2달이 다 되어간다.
개발부터 출시(배포) 유지보수를 하다보니 시간이 쏜살같이 지나간거 같다.
이번 이 글에서 적을 내용이 이번에 CI/CD를 위해 구축한 jenkins pipeline의 과정을 간단하게 적어놓을려고 한다. (<del>나 졸라 대단한 듯</del>)
본 글쓴이가 퇴근 후 끄적이기 때문에 3일에 걸쳐 3편으로 연재 될 예정이다.(골골..)
(눙물...)</p>
<h2 id="시작">시작</h2>
<p>일단 우리 앱은 AWs EC2 환경에서 docker-compose를 이용하여 배포를 진행했었다.
그 점을 이용해 기존 docker-compose file에 jenkins official image를 pull 받아와 컨테이너를 같이 띄울 생각으로 추가 후 docker-compose를 진행하였는데 되지 않았다.....(왜지...?)
아직까지 이유를 찾지 못하고 있다.</p>
<p>그래서 차선책으로 EC2 환경에 접속해 docker hub에서 jenkins:lts image를 pull 받아 docker-compose를 올린 후 jenkins image만 따로 run하는 방법으로 진행하였다.(port는 8080:8080 사용)
참고로 jenkins image를 받을 때 lastest는 비추천한다고 한다. 오류가 발생하는 경우가 있다고 하여 lts를 사용하여 image를 pull 받았다.</p>
<p>아 맞다. EC2 인바운드 규칙에 jenkins를 추가하여야 한다.(아까 기술한 컨테이너 port와 동일하게 설정하면 된다. 8080^^)</p>
<p>이렇게 EC2와 container를 올린 뒤 EC2의 퍼블릭 ip에 8080 port로 접속을 하게 되면 아래의 사진과 같은 화면이 뜬다.
<img src="https://images.velog.io/images/samdaso-o/post/2d9fc5b9-d367-432c-b893-199c9d11ae6a/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.29.20.png" alt=""></p>
<p>이때 필요한 password는 EC2에서 jenkins를 run할때의 logs를 보면 나온다.</p>
<blockquote>
<p>docker logs [container id]</p>
</blockquote>
<p>그럼 아래의 사진 글 밑에 암호가 나오게 된다. 그 값을 복사해 입력란에 기입한다.
<img src="https://images.velog.io/images/samdaso-o/post/5813c1d7-92e5-49b2-8d98-e6be4d0ea9a4/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.30.50.png" alt=""></p>
<p>입력한 후 아래와 같은 화면이 나오게 된다. 본 글쓴이는 jenkins을 믿기에 jenkins이 제시한 plugins를 선택하였닼ㅋㅋㅋㅋㅋㅋㅋ^^</p>
<p><img src="https://images.velog.io/images/samdaso-o/post/dd2bfde8-ae05-4059-acf7-ea1b2948c60b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.31.23.png" alt=""></p>
<p>그럼 아래의 사진과 같이 jenkins이 혼자서 열심히 일하기 시작한다. 한 5분정도 걸렸던것 같다.
<img src="https://images.velog.io/images/samdaso-o/post/a0c1a129-a744-44ff-b11f-61b7ffa5156b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.31.53.png" alt=""></p>
<p>이 화면뒤로 계정 회원가입 페이지가 나오게 되는데 가입을 진행하고 넘어가면 아래와 같은 나를 무척이나 환영해주는 홈페이지가 나온다.
<img src="https://images.velog.io/images/samdaso-o/post/d73151cd-f703-44f2-82d7-612ea1e798ff/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-12-14%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.54.05.png" alt=""></p>
<p>여기까지 왔다면 당신은 멋쟁이</p>
<p>다음편에는 jenkins 컨테이너 내에 ssh key를 생성하고 github에는 pub-key, jenkins에도 key를 등록하고 hook 초기 설정을 기술하도록 하겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[mysql 이모티콘?]]></title>
            <link>https://velog.io/@samdaso-o/mysql-%EC%9D%B4%EB%AA%A8%ED%8B%B0%EC%BD%98</link>
            <guid>https://velog.io/@samdaso-o/mysql-%EC%9D%B4%EB%AA%A8%ED%8B%B0%EC%BD%98</guid>
            <pubDate>Thu, 11 Nov 2021 09:37:08 GMT</pubDate>
            <description><![CDATA[<p>이번에 입사한 회사에서 프로젝트를 진행하던 도중 Android/iOS 등에서 사용하는 이모티콘을 mysql에서 처리하지 못하는 이슈가 발생하였다.
<img src="https://images.velog.io/images/samdaso-o/post/7f83f856-955a-411f-9a30-182acbda1d6a/%E3%85%81%E3%84%B4%E3%85%87%E3%84%B9.jpeg" alt="">
(멘붕)</p>
<p>구글링을 하던 도중 발견한 사실..
Android/iOS 등에서 사용하는 이모티콘은 특수한 경우를 제외하고는 4비트이고 utf8로 인코딩이 설정된 MySQL에서 받을 수 있는 문자열은 3바이트까지만 지원한다는 내용이였다.</p>
<p>해결 방법
이모티콘을 mysql에 저장하기위해서는 인코딩을 변경해주어야한다. 인코딩은 문자 하나당 4바이트를 지원하는 utf8mb4로 변경하여야 했는데,
django settings.py에서 DATABASE 부분에 </p>
<pre><code>&quot;OPTIONS&quot;: {&quot;charset&quot;: &quot;utf8mb4&quot;},</code></pre><p>옵션을 추가하여 해결하였다.</p>
<p>화이팅! ^^</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Encoding...Decoding...]]></title>
            <link>https://velog.io/@samdaso-o/Encoding...Decoding</link>
            <guid>https://velog.io/@samdaso-o/Encoding...Decoding</guid>
            <pubDate>Sun, 31 Oct 2021 05:48:52 GMT</pubDate>
            <description><![CDATA[<h2 id="encoding-decoding">Encoding? Decoding?</h2>
<p>솔직히 많이 보고 알게 모르게 써왔던 것 같다. 이번에 정확한 개념을 확실히 정리해볼려고 한다.</p>
<h4 id="encoding">Encoding</h4>
<p>모든 문자 또는 기호에 하나씩 일련번호를 부여해 컴퓨터에 저장 또는 통신에 사용할 목적으로 부호화하는 방법이다. 간단하게 말하자면 입력한 문자나 기호를 컴퓨터가 이용할 수 있는 신호로 만드는 것을 뜻한다. (인코딩 = 부호화 = 암호화 / 같은 의미입니다.)</p>
<h4 id="decoding">Decoding</h4>
<p>인코딩의 반대 개념으로, 인코딩된 문자 또는 기호를 인코딩되기 전으로 돌리는 방법을 디코딩이라고 한다.</p>
<h4 id="encodingdecoding을-사용하는-이유">Encoding/Decoding을 사용하는 이유?</h4>
<p>프로그래밍 언어가 다른 것들을 하나의 규격으로 표준화시켜 사용자의 요구에 따라 사용할 수 있도록 하기 위해서 사용한다고 한다. 인코딩과 디코딩 과정은 사실 표현방식을 바꾸는 것이라고 이해하면 될꺼 같다. 인코딩과 디코딩 과정을 수행하는 와중에 정보의 손실이 없다는 장점이 있다.</p>
<h4 id="다양한-encoding">다양한 Encoding</h4>
<ul>
<li>대표적인 몇개만 알아보도록 하겠습니다.</li>
</ul>
<ol>
<li><p>ASCII code (아스키 코드)
0번부터 127번까지 문자에 대해 각각의 번호를 지정한 집합체로 가장 기초가 되고 있는 문자 코드이다.
7비트방식으로, 모든 문자를 1byte안에서 표현할 수 있다는 장점이 있다. 하지만 로마자 알파벳, 아라비아숫자, 일부 특수문자들만 사용할 수 있다는 단점이 있다.</p>
</li>
<li><p>UTF-8 / UTF-16 (유니코드)
아스키 코드는 로마자 알파벳만 표현 가능하다는 단점을 개선한 코드로, 전 세계 모든 글자를 다 표현할 수 있는 문자 처리 방식이다. 유니코드는 전세계 모든 문자를 각각 1byte 이상의 크기로 표현할 수 있게 할 수 있는 방식이다. 기존의 인코딩의 문자열보다 크기가 크다는 단점이 있다.</p>
</li>
<li><p>Base 64
Base64는 ASCII 중 제어문자와 일부 특수문자를 제외한 64개의 문자 코드에 영향을 받지 않는 공통 ASCII 문자만 사용한다. base 64는 6비트방식으로 6비트씩 자른 뒤 6비트에 해당하는 문자를 base64 table에 색인된 값을 찾아 치환하는 방식으로, 이 방식은 2비트가 남는 데이터가 버려지는 현상이 발생되는데, 그럼에도 이 방식을 사용하는 이용하는 이유는 기존의 아스키 코드 방식은 시스템간 데이터를 전달하기에 안전하지 않는 문제 때문이다. 모든 binary datark 아스키코드에 포함되지 않아 제대로 읽지 못하는 단점이 존재하는데, 반면 base64는 제어문자와 일부 특수문자를 제외하고는 읽을 수 있다. </p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Redis 기본정리]]></title>
            <link>https://velog.io/@samdaso-o/Redis-%EA%B8%B0%EB%B3%B8%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@samdaso-o/Redis-%EA%B8%B0%EB%B3%B8%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 24 Oct 2021 06:09:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/samdaso-o/post/6aa0a4b3-0152-43fa-96cd-de4e4e9ad9db/Redis.png" alt=""></p>
<h2 id="redis란">Redis란?</h2>
<p>Redis는 키와 값을 기반으로 하는 메모리 데이터 스토어이다.
키와 값을 기반으로 하기 때문에 쿼리를 처리할 필요없이 바로 가져올 수 있고, 메모리에 담기 때문에 속도가 매우 빠르다.</p>
<h3 id="지원하는-데이터-구조">지원하는 데이터 구조</h3>
<ol>
<li>string : 간단한 키와 값으로 된 구조</li>
<li>list : 배열 형식으로 된 구조, FIFO, LIFO을 할때 매우 유용하다. 하지만 중간에 데이터를 넣는것은 취약하다.</li>
<li>sets : 순서가 필요없는 string 데이터 집합이다. 중복을 허용하지 않는다.(같은 데이터가 들어오면 하나로 취급)</li>
<li>hash : 키와 값을 여러개 가진 구조</li>
</ol>
<h3 id="redis-특징">Redis 특징?</h3>
<p>redis는 싱글 스프레드이다. 한번에 하나의 명령어만 처리 가능하고, 데이터가 나눠져 여러개의 패킷이 들어온다면, 그 패킷이 전부 합쳐져 하나의 명령어가 될때까지 실행되지 않는다.
이에 따라 요청이 타임 아웃이 나는 경우들이 있다. 키를 전부 호출한다던지 이런 경우 타임 아웃이 발생할 수 있으니, 이에 따른 알맞은 로직을 구성하도록 하는것이 좋겠다.</p>
<h3 id="redis-replication">Redis replication?</h3>
<p>redis 구성 중에 요청 분산과 데이터 이중화를 위해 db_replication처럼 master/slave 구조를 가질 수 있다. 
이에 따라 redis cluster 형태가 나타날 수 있는데, 하나의 클러스터가 여러개의 master를 가지고 있고, 그에 따라 slave를 가지고 있는 구조를 사용하는데, 이때 하나의 master가 죽으면 그 밑에 존재하던 slave 가 승격하여 master의 역활을 대신하는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TCP/IP , UDP]]></title>
            <link>https://velog.io/@samdaso-o/TCPIP-UDP</link>
            <guid>https://velog.io/@samdaso-o/TCPIP-UDP</guid>
            <pubDate>Thu, 21 Oct 2021 04:18:30 GMT</pubDate>
            <description><![CDATA[<h2 id="tcpip란">TCP/IP란?</h2>
<h4 id="tcp란">TCP란</h4>
<p>transmission control protocol으로 두 호스트가 교환하는 데이터와 승인 메세지의 형식을 정의한다. 서버와 클라이언트간의 데이터를 신뢰성있게 전달하기 위해 만들어진 규약이다.
TCP는 네트워크에 연결된 컴퓨터에서 실행되는 프로그램 간에 일련의 옥텟(데이터, 메세지, 세그먼트라는 블록 단위)를 안정적으로, 순서대로, 에러없이 교환할 수 있게 한다.</p>
<h4 id="ip란">IP란</h4>
<p>internet protocol으로 컴퓨터와 컴퓨터간의 데이터를 전송하기 위해서, 각 컴퓨터마다 부여된 주소이다. IP는 TCP와는 달리 데이터의 재조합이나 손실여부 확인이 불가능하며, 단지 데이터를 전달하는 역할만을 담당한다. IP주소는 다른주체에게 받는 주소이므로, 바뀔수 있다.</p>
<h3 id="udp란">UDP란?</h3>
<p>UDP란 ip를 사용하는 네트워크내 컴퓨터들간에 메세지들을 교환할때 제한된 서비스를 제공하는 통신 프로토콜이다.</p>
<p>그럼 여기서 드는 의문점, TCP와 UDP의 차이점..? 언제 사용되는지?</p>
<h3 id="tcp와-udp의-차이점">TCP와 UDP의 차이점</h3>
<p>두 프로토콜은 모두 패킷을 한 컴퓨터에서 다른 컴퓨터로 전달해주는 IP 프로토콜을 기반으로 구현되어 있지만, 서로 다른 특징을 가지고 있다. 일단 TCP는 요청,승인메세지등 쌍방향 통신을 하지만, UDP는 그저 송신만 하는 일방적인 통신을 한다. 이 때문에 UDP가 TCP보다 속도면에서는 우세하다.
신뢰성이 요구되는 애플리케이션에서는 TCP를 사용하고 간단한 데이터를 빠른 속도로 전송하고자 하는 애플리케이션에서는 UDP를 사용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Stack? Queue? 드루와....]]></title>
            <link>https://velog.io/@samdaso-o/Stack-Queue-%EB%93%9C%EB%A3%A8%EC%99%80</link>
            <guid>https://velog.io/@samdaso-o/Stack-Queue-%EB%93%9C%EB%A3%A8%EC%99%80</guid>
            <pubDate>Wed, 13 Oct 2021 07:23:49 GMT</pubDate>
            <description><![CDATA[<h2 id="stack-queue">Stack? Queue?</h2>
<h2 id="너네-누구냐">너네 누구냐..?</h2>
<p>프로그래머스에서 알고리즘 문제를 풀던 도중 stack, queue라는 개념을 알게 되었다.
이번에 알게 된 stack과 queue를 정리하고 공유하기 위해 블로깅한다 ㅎㅎ</p>
<h3 id="stack이란">Stack이란?</h3>
<p>입력과 출력이 한 곳(방향)으로 제한된 것을 말한다.
여기서 LIFO라는 개념이 등장한다.</p>
<h3 id="lifo란">LIFO란?</h3>
<p>last in first out으로 이름 그대로 가장 나중에 들어온 것이 가장 먼저 나가는 것으로 주로 함수의 콜스택, 문자열 역순 출력, 연산자 후위 표기법등에서 사용된다.
<img src="https://images.velog.io/images/samdaso-o/post/df78aaaa-d4dc-4de7-ab3f-fe25960466bb/stack.png" alt=""></p>
<p>크게 5가지의 명령어가 존재한다. (파이썬은 리스트로 스택을 흉내낸다.)</p>
<ul>
<li><p>데이터 넣음 : push()
  파이썬에는 push()가 존재하지 않아, append()를 사용한다. 마지막 원소를 추가한다.</p>
</li>
<li><p>데이터 최상위 값 뺌 : pop()
  파이썬에는 pop()이 존재한다. 마지막 원소를 삭제한다.</p>
</li>
<li><p>비어있는 지 확인 : isEmpty()
  조건문으로 len()함수를 통해 확인 가능</p>
</li>
<li><p>꽉차있는 지 확인 : isFull()
  조건문으로 len()함수를 통해 확인 가능</p>
</li>
<li><p>sp : 데이터가 새로 추가되고, 빠질때 위치를 확인하기 위한 것</p>
</li>
</ul>
<h3 id="queue이란">Queue이란?</h3>
<p>입력과 출력을 한 쪽 끝으로(front, rear)으로 제한된 것을 말한다.
큐의 가장 첫 원소를 front, 끝 원소를 rear라고 부른다. 큐는 들어올 때 rear로 들어오지만, 나올 때는 front부터 빠지는 특성을 가지고, 접근방법은 가장 첫 원소와 끝 원소로만 가능하다.
여기서 FIFO라는 개념이 등장한다.</p>
<h3 id="fifo란">FIFO란?</h3>
<p>first in first out으로 이름 그대로 가장 먼저 들어온 것이 가장 먼저 나가는 개념으로, 버퍼 또는 많은 양의 데이터가 입력된 것을 처리하지 못하는 상황에 주로 사용된다.
<img src="https://images.velog.io/images/samdaso-o/post/ee400b93-5820-4c23-9727-3903518b253e/queue.png" alt=""></p>
<p>LIFO와 마찬가지로 크게 4가지의 명령어가 존재한다. (마찬가지로 리스트로 큐를 흉내낸다.)</p>
<ul>
<li><p>데이터 넣음 : enQueue()
파이썬에서는 append()(마지막원소로 삽입) 또는 insert(0, x)(첫번째 원소로 삽입)를 사용한다.</p>
</li>
<li><p>데이터 뺌 : deQueue()
파이썬에서는 pop(0)으로 첫번째 원소를 삭제한다.</p>
</li>
<li><p>비어있는 지 확인 : isEmpty()
조건문으로 len()함수를 통해 확인 가능</p>
</li>
<li><p>꽉차있는 지 확인 : isFull()
조건문으로 len()함수를 통해 확인 가능</p>
</li>
<li><p>sp : 데이터가 새로 추가되고, 빠질때 위치를 확인하기 위한 것</p>
</li>
</ul>
<p>collections의 모듈 중 deque 자료구조가 있으니, queue를 작성 할때 사용하면 좋을 듯 싶다.
( popleft() 등등 여러 메소드 제공)</p>
<h4 id="푼-문제-깃허브-링크">푼 문제 깃허브 링크</h4>
<p>프로그래머스-기능개발.py : <a href="https://github.com/Samdaso-o/python_pratice/blob/main/Programmers/%EC%8A%A4%ED%83%9D-%ED%81%90/%EA%B8%B0%EB%8A%A5%EA%B0%9C%EB%B0%9C.py">https://github.com/Samdaso-o/python_pratice/blob/main/Programmers/%EC%8A%A4%ED%83%9D-%ED%81%90/%EA%B8%B0%EB%8A%A5%EA%B0%9C%EB%B0%9C.py</a></p>
<p>사진 출처 : 위키백과</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hash에 관하여]]></title>
            <link>https://velog.io/@samdaso-o/Hash%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC</link>
            <guid>https://velog.io/@samdaso-o/Hash%EC%97%90-%EA%B4%80%ED%95%98%EC%97%AC</guid>
            <pubDate>Mon, 11 Oct 2021 04:45:37 GMT</pubDate>
            <description><![CDATA[<h2 id="hash란">Hash란?</h2>
<p>임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수이다. 해시 함수에 의해 얻어지는 값은 해시 값, 해시 코드, 해시 체크섬 또는 간단하게 해시라고 한다.  —by 위키백과—</p>
<p>간단하게 요점만 말하자면 단방향 암호화 기법으로 해시함수(해시 알고리즘)를 이용하여 고정된 길이의 암호화된 문자열로 바꿔버리는 것을 해시라고 한다.</p>
<p>같은 자료를 묶어서 파악할 수 있는 것이 장점이자 특징이고, 특정 입력에 대해 항상 같은 해시 값을 리턴하기 때문에 이를 이용해 인증이라든지 여러 방면에서 사용가능하다.</p>
<h3 id="hash-table">hash table?</h3>
<p>hash table이란 , key와 value를 가지고 있는 자료구조로 파이썬에서는 딕셔너리를 떠올리면 이해가 빠를 것이다. 주로 효율적인 검색에 활용되고, 알맞는 키로 그 키에 색인되있는 주소를 찾아가 value를 저장 및 출력하는 구조이다. 이때 색인된 주소를 산출하는 것을 <strong><em>해쉬함수</em></strong> 라고 부른다.
<img src="https://images.velog.io/images/samdaso-o/post/6f2eaa26-dc96-4392-bf4a-3b1f4f6cf112/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-10-11%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.14.44.png" alt=""></p>
<p>그런데 이때 문제가 발생하는 경우가 생기는데, 다른 데이터값임에도 같은 키를 가지게 된다면?, 
이러한 상황을 <strong><em>해쉬 충돌</em></strong> 이라고 한다.</p>
<h3 id="hash-collision-solution">hash collision solution?</h3>
<p>크게 두가지의 방법이 존재한다.</p>
<h4 id="1-chaining">1. Chaining</h4>
<p>이미 사용중인 주소를 피하지 않고, 데이터를 연결하여 저장하는 방식이다. 각 색인된 주소별로 연결리스트(Linked list)를 할당하여, 데이터를 삽입하다가 충돌이 일어나면 연결리스트로 데이터를 연결한다.</p>
<h4 id="2-open-addressing">2. Open addressing</h4>
<p>해시 충돌이 발생하면, 그 주소에 저장하지 않고 비어있는 주소에 저장하는 방법이다.
크게 세가지 방식이 있는데,</p>
<ul>
<li>Linear probing : 충돌이 발생하면, 몇개의 주소를 건너뛰어 저장하는 방식</li>
<li>Quadratic probing : 충돌이 발생하면, 제곱만큼 건너뛰어 저장하는 방식</li>
<li>Double hashing : 충돌이 발생하면, 다른 해쉬함수를 적용시켜 그 결과값을 이용하는 방식</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git rebase? squash?]]></title>
            <link>https://velog.io/@samdaso-o/Git-rebase-squash</link>
            <guid>https://velog.io/@samdaso-o/Git-rebase-squash</guid>
            <pubDate>Sun, 10 Oct 2021 11:44:18 GMT</pubDate>
            <description><![CDATA[<h2 id="git-rebase-squash">Git rebase? squash?</h2>
<p>Git rebase : 다른 branch에 존재하던 commit들이 합쳐지지 않고 개별적으로 master branch에 추가된다 / 브랜치 병합 시 merge 기록이 따로 남지 않아 하나의 브랜치에서 작업한 것으로 보여진다
<img src="https://images.velog.io/images/samdaso-o/post/23e58db7-5e94-4064-9825-97c16a75897e/0fc55e730fa543c887c434b08facc9dd-0001.jpg" alt=""></p>
<h4 id="-제가-손으로-그린-그림이라-죄송합니다ㅎㅎㅎ">-제가 손으로 그린 그림이라 죄송합니다..ㅎㅎㅎ</h4>
<p>Git squash : 다른 branch에 존재하는 commit들을 하나로 합쳐 새로운 commit을 만들어 그 commit만 master branch에 추가한다. / commit history를 깔끔하게 하기 위해 사용된다.
<img src="https://images.velog.io/images/samdaso-o/post/9cbb12fe-1bed-418b-84f4-e4a0eea47c87/be6fb5e551254b85994909f2b408db8f-0001.jpg" alt=""></p>
<h4 id="-제가-손으로-그린-그림이라-다시-한번-죄송합니다ㅎㅎㅎ">-제가 손으로 그린 그림이라 다시 한번 죄송합니다..ㅎㅎㅎ</h4>
<p>두가지의 가장 큰 차이점은 parent의 차이이다. squash는 새로운 커밋을 생성해 merge해 새로운 커밋만 parent로 바라보지만, rebase는 모두 각각의 하나의 parent를 가지게 된다.</p>
<h3 id="tip">tip</h3>
<p>Dev branch - feature간의 머지 : squash &amp; merge가 유용함. 매번 작업하는 feature는 지저분한 히스토리를 가지고 있을 확률이 높다. 또한 feature branch를 merge 후 다시 재사용하지 않는다는 점에서 기존의 commit을 전부 남길 필요가 없다.</p>
<p>master - Dev branch간의 머지 : rebase &amp; merge가 유용함. dev를 머지할때 굳이 별도의 새로운 커밋을 생성할 필요가 없기 때문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cache Memory]]></title>
            <link>https://velog.io/@samdaso-o/Cache-Memory</link>
            <guid>https://velog.io/@samdaso-o/Cache-Memory</guid>
            <pubDate>Mon, 04 Oct 2021 05:18:28 GMT</pubDate>
            <description><![CDATA[<p>Cache Memory란?
속도가 서로 다른 장치들 사이의 병목현상을 줄이기 위한 메모리를 뜻한다.</p>
<p>CPU가 주기억장치에서 데이터를 읽어올 때, 자주 사용하는 데이터를 캐시메모리에 저장하고, 다시 사용시에 주기억장치에서 가져오는 것이 아니라 캐시 메모리에서 먼저 가져와 속도를 향상 시킨다.</p>
<p>단점으로는 용량이 작고, 비용이 비싸다는 단점이 있다.</p>
<p>CPU에는 캐시메모리가 대체적으로 2~3개가 사용된다. (L1, L2, L3)
L1은 가장 크고 빠른 캐시 메모리로 여기서 찾지 못하면 L2, L3 이런식으로 진행된다.</p>
<p>만약 L1캐시가 64kb이라면, 32로 나누어 하나는 명령어를 처리하기 전의 명령어를 임시 저장하고, 나머지 하나는 실행 후 명령어를 임시저장한다.</p>
<p>캐시메모리가 작동되는 원리는 시간 지역성과 공간 지역성이 있는데,
시간 지역성이란 for같은 반복문에 사용되어 가져온 데이터는 다시 한번 가져올 가능성이 높은 것 
공간 지역성이란 인덱싱 같은 접근 시, 참조된 데이터 근처에 있는 데이터가 잠시 후 다시 사용될 가능성이 높은 것</p>
<p>CPU가 요청한 데이터가 캐시에 있으면 Cache Hit, 없으면 Cache miss</p>
<p>Cache miss에도 3가지 경우가 있는데,
-cold miss : 처음 호출하는 메모리 주소를 불러서 나는 미스
-conflict miss: 캐시 메모리에 다른 데이터를 저장해야 되는데 데이터가 같은 캐시 메모리 주소에 할당되서 나는 미스
-capacity miss : 캐시메모리의 공간이 부족하면 나는 미스</p>
<p>캐시 메모리 저장 방식 3가지
-Direct mapped cache : 기본적인 구조로, 캐시 메모리의 한 주소에 대응되는 다대일 방식
<img src="https://images.velog.io/images/samdaso-o/post/fd615cdb-b654-4fed-b3d5-0c54b5469b7d/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-10-04%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%202.14.50.png" alt="">
간단하고 빠른 장점이 있지만, confilct miss가 발생한다. 위의 사진처럼 같은 색깰의 데이터를 동시에 사용될때 발생한다.</p>
<p>-Fully associative cache : 비어있는 캐시 메모리에 마음대로 주소를 저장하는 방식, 저장은 매우 쉽지만 찾을때 모든 캐시를 검색해야 하므로 조건이나 규칙이 없어서 오래걸릴수 있다.</p>
<p>-Set associative cache : Direct + fully방식으로 특정 행을 지정하고, 그 행안에 어떤열이든 비어있으면 저장하는 방식으로 두가지 방식의 보완 방식이다. 속도는 중간</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Docker Container에서 vim 설치방법]]></title>
            <link>https://velog.io/@samdaso-o/Docker-Container%EC%97%90%EC%84%9C-vim-%EC%84%A4%EC%B9%98%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@samdaso-o/Docker-Container%EC%97%90%EC%84%9C-vim-%EC%84%A4%EC%B9%98%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 24 Sep 2021 06:34:19 GMT</pubDate>
            <description><![CDATA[<p>docker 컨테이너 환경에서 파일을 수정해야되는 상황이 닥쳤다.
vim이 떠올랐고 사용하게 되었다. 이번에 알게된 docker container에서 vim 설치방법을 적어놓을려고 한다.</p>
<p>간단하다.</p>
<blockquote>
<p>apt-get update</p>
</blockquote>
<p>마지막으로 </p>
<blockquote>
<p>apt-get install vim</p>
</blockquote>
<p>끝이다 ㅎㅎ</p>
<p>vim 사용법은 vi [파일명]으로 접속해 i 를 눌러 insert mode로 바꾼 후, 수정하면된다.
수정완료하고 :wq는 저장 후 나가기, :q는 저장하지않고 나가기이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Docker]]></title>
            <link>https://velog.io/@samdaso-o/Docker</link>
            <guid>https://velog.io/@samdaso-o/Docker</guid>
            <pubDate>Sun, 29 Aug 2021 11:24:01 GMT</pubDate>
            <description><![CDATA[<h2 id="docker-순서">Docker 순서</h2>
<ol>
<li>생성한 프로젝트에 Dockerfile 생성</li>
<li>Dockerfile에 아래의 내용 추가
<img src="https://images.velog.io/images/samdaso-o/post/dd865c59-002a-4792-b3e1-4acd4e82d96a/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-29%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.46.45.png" alt=""></li>
<li>Dockerfile 작성 후, image build 하기(아래의 명령어)
(맥북 m1 기준입니다.)</li>
</ol>
<ul>
<li>ex) docker buildx build --platform=linux/amd64 -t &#39;dockerhub id&#39;/&#39;image name&#39;:&#39;version&#39;</li>
</ul>
<p>--갈림길이다. 이제 여기서 AWS EC2에 배포를 할 경우에는 docker hub에 push를 해야하고 아닌 경우에는 image를 run하면 된다.
아래의 경우는 AWS EC2에 배포하는 경우이다.</p>
<ol start="4">
<li><p>터미널에서 docker에 로그인을 한다.</p>
<blockquote>
<p>$ docker login</p>
</blockquote>
</li>
<li><p>docker hub에 push 한다.</p>
<blockquote>
<p>$ docker push &#39;docker id&#39;/repository_name:tag_name</p>
</blockquote>
</li>
<li><p>성공적으로 push가 되었는지 docker hub &gt; repositories에서 확인한다.</p>
</li>
</ol>
<p>--EC2가 정상적으로 접속해 있단 가정하에 아래의 순서를 진행하기 바란다.</p>
<p>7.가장 먼저 EC2 server에 docker를 설치한다.</p>
<blockquote>
<p>$ sudo apt update
$ sudo apt install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL <a href="https://download.docker.com/linux/ubuntu/gpg">https://download.docker.com/linux/ubuntu/gpg</a> | sudo apt-key add -
$ sudo add-apt-repository &quot;deb [arch=amd64] <a href="https://download.docker.com/linux/ubuntu">https://download.docker.com/linux/ubuntu</a> bionic stable&quot;
$ sudo apt update
$ apt-cache policy docker-ce
$ sudo apt install docker-ce</p>
</blockquote>
<p>혹시 위의 명령어를 다 입력하고도 docker 설치가 확인되지 않는다면, 아래의 명령어를 입력하기 바란다.</p>
<blockquote>
<p>$ sudo chmod 666 /var/run/docker.sock
$ sudo setfacl --modify user::rw /var/run/docker.sock</p>
</blockquote>
<ol start="8">
<li><p>docker가 성공적으로 설치 되었다면 일단 login을 진행한다.</p>
</li>
<li><p>그 다음 pull을 통해서 올렸던 Image를 가져온다.</p>
<blockquote>
<p>$ sudo docker pull &#39;docker id&#39;/repository_name:tag_name</p>
</blockquote>
</li>
<li><p>성공적으로 받아왔다면 아래의 명령어로 run한다.
<img src="https://images.velog.io/images/samdaso-o/post/84218566-a0bf-4af4-8fa3-409807ea6eb9/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-29%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.21.52.png" alt=""></p>
</li>
</ol>
<p>성공 !!</p>
<p><img src="https://images.velog.io/images/samdaso-o/post/e529f9c8-8c02-4856-a014-7bec19430aa0/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-29%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.22.51.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[go..? go..! 3탄]]></title>
            <link>https://velog.io/@samdaso-o/go..-go..-3%ED%83%84</link>
            <guid>https://velog.io/@samdaso-o/go..-go..-3%ED%83%84</guid>
            <pubDate>Thu, 26 Aug 2021 11:02:14 GMT</pubDate>
            <description><![CDATA[<p>이제 int를 다뤄보겠다.
곱셉을 출력하는 간단한(..?) 코드다.</p>
<p>file_name : main.go</p>
<blockquote>
<p>import &quot;fmt&quot;</p>
<p>func multiply(a int, b int) int {
return a * b
}</p>
<p>func main() {
fmt.Println(multiply(2, 2))
}</p>
</blockquote>
<p>출력값 : 4
간단하게 코드를 풀어보자면 a와 b 변수에는 타입을 int 선언을 해주었고, multiply가 출력될때의 타입 int로 지정을 해주었다.(타입 지정은 필수다!)</p>
<p>여기서 코드를 좀 더 축약가능하다.
multiply(a int, b int)를 multiply(a, b int)로 축약이 가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[go..? go..! 2탄]]></title>
            <link>https://velog.io/@samdaso-o/go..-go-8m8ysyok</link>
            <guid>https://velog.io/@samdaso-o/go..-go-8m8ysyok</guid>
            <pubDate>Thu, 26 Aug 2021 02:25:12 GMT</pubDate>
            <description><![CDATA[<p>go에는 파이썬과 다르게 변수와 상수가 공존하는데,
변수(variables)는 값을 변경 가능하다.
하지만 상수(constants)는 변수지만 값의 변경이 불가능하다.
자 이제 사용을 해보겠다.
go는 var인지 const인지도 선언을 해주어야 하지만, type도 선언을 해주어야 한다.
const로 작성해 내 이름을 출력하는 코드를 하나 적어보겠다.</p>
<p>file_name : main.go</p>
<blockquote>
<p>pakage main</p>
<p>import &quot;fmt&quot;</p>
<p>func main() {
  const name string = &quot;han&quot;
  fmt.Println(name)
}</p>
</blockquote>
<p>출력값 : han</p>
<p>만약 const를 선언한 것에서 다시 name을 다시 선언할려고 한다면 에러가 난다. 아래의 코드를 참조할 것.</p>
<p>file_name : main.go</p>
<blockquote>
<p>pakage main</p>
<p>import &quot;fmt&quot;</p>
<p>func main() {
  const name string = &quot;han&quot;
  name = &quot;kim&quot;
  fmt.Println(name)
}</p>
</blockquote>
<p>출력값 : error</p>
<p>파이썬을 사용하던 나는 지금 타입을 쓸때마다 선언해주어야 한다는 것에 매우 불편함을 느꼈다.
그때 안것이 바로 아래의 코드이다.</p>
<p>file_name : main.go</p>
<blockquote>
<p>pakage main</p>
<p>import &quot;fmt&quot;</p>
<p>func main() {
  name := &quot;han&quot;
  name = &quot;kim&quot;
  fmt.Println(name)
}</p>
</blockquote>
<p>출력값 : kim</p>
<p>&#39;:=&#39; 는 축약형으로 타입을 값에 따라 타입을 찾아서 적용시켜준다. 값이 false라면 타입 bool을 자동 적용시켜준다.
만약 축약형으로 변수를 선언한 뒤 변수의 타입과 다른 타입을 다시 선언할려고 하면 에러가 발생할 것이다.</p>
<p>file_name : main.go</p>
<blockquote>
<p>pakage main</p>
<p>import &quot;fmt&quot;</p>
<p>func main() {
  name := false 
  name = &quot;kim&quot;
  fmt.Println(name)
}</p>
</blockquote>
<p>출력값 : error</p>
<p>또한 &#39;:=&#39;는 func() 밖에서 사용이 불가능하다.
만약 밖에서 변수를 선언하고 싶다면,</p>
<blockquote>
<p>var name bool = false</p>
</blockquote>
<p>위와 같이 선언 변수 타입을 다 선언을 해주면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[go..? go..!]]></title>
            <link>https://velog.io/@samdaso-o/go..-go</link>
            <guid>https://velog.io/@samdaso-o/go..-go</guid>
            <pubDate>Wed, 25 Aug 2021 15:19:26 GMT</pubDate>
            <description><![CDATA[<p>go언어는 컴파일을 하기 위해선 파일이름을 main으로 선언해주어야 한다.
진입점이 main이기에 컴파일러는 패키지 이름이 main인 것부터 찾기 때문이다.
만약 오픈소스나 공유를 위한 라이브러리를 만든다면 이런경우에는 main.go를 사용하지 않아도 된다.</p>
<p>가장 기초적으로 &#39;Hello world&#39;를 프린트 해보겠다.
첫줄에는 메인 패키지를 선언한다.
-file name : main.go</p>
<blockquote>
<p>package main</p>
<p>import &quot;fmt&quot;</p>
<p>func main(){
fmt.Println(&quot;Hello world&quot;)
}</p>
</blockquote>
<p>첫줄에는 내가 작성할 패키지의 이름을 적어 선언해준다. 
그리고 go언어는 다른 파이썬 언어와 다르게 func main()을 선언해주어야 한다.
이것이 이 프로그램의 시작점이 되는 부분이다.
자동적으로 컴파일러는 main pakage와 그 안에 있는 main func을 먼저 찾고 실행시킨다.
fmt는 formatting의 약자로 여러가지 func기능을 담고있다. 그중 프린트기능이 가능한 Println을 사용했다.
만약 vs code를 사용한다면, fmt을 입력만 하면 자동으로 위쪽에서 import를 해주는 기능이 있으니 참조하길 바란다.</p>
<ul>
<li>대문자로 시작하는 func??</li>
<li>file name : practice.go<blockquote>
<p>package practice</p>
<p>import &quot;fmt&quot;</p>
<p>func hi(){
fmt.Println(&quot;hi&quot;)
}</p>
<p>func Hi(){
fmt.Println(&quot;Hi&quot;)
}</p>
</blockquote>
</li>
</ul>
<p>위와 같이 다른 파일에서 패키지를 선언하고 두가지의 func을 만들었다.
그리고 처음에 작성한 main 패키지에 적용을 시켜보겠다.
-file name : main.go</p>
<blockquote>
<p>package main</p>
<p>import (&quot;fmt&quot;
        &quot;xxx/xxx/learngo/practice&quot;</p>
<p>func main(){
fmt.Println(&quot;Hello world&quot;)
practice.Hi()
}</p>
</blockquote>
<p>func을 대문자로 작성한 func은 import가 되지만 소문자로 작성한 func은 import가 되지 않는다. 소문자로 작성하면 pravite func으로 취급되 import 되지 않는다. 하지만 대문자로 작성한다면, 다른 패키지에서 import해서 사용가능하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[code kata 5-1]]></title>
            <link>https://velog.io/@samdaso-o/code-kata-5-1</link>
            <guid>https://velog.io/@samdaso-o/code-kata-5-1</guid>
            <pubDate>Tue, 17 Aug 2021 01:45:31 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/samdaso-o/post/03726915-058c-4fc1-809b-0ff09a012b2f/%E1%84%86%E1%85%AE%E1%86%AB%E1%84%8C%E1%85%A6.jpeg" alt="">
코딱지 여러분 잘 지내셨죠?
오늘 재밌는 문제를 가지고 왔어요!</p>
<h4 id="문제">문제</h4>
<p><img src="https://images.velog.io/images/samdaso-o/post/c0625f9f-27b6-4f17-8a67-01dd64b668cb/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-17%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.36.18.png" alt="">
sort를 사용하지 않고 숫자 배열을 정렬하는 알고리즘을 구현하는 문제예요.</p>
<h4 id="생각해보기">생각해보기</h4>
<p>반복문 두개를 사용하여 한자리를 반복해 그 뒤의 값을 전부 비교해 그 중 가장 작은 값을 그 반복을 시작한 그 자리와 바꾼다.
<img src="https://images.velog.io/images/samdaso-o/post/97852aa9-4e4e-4fec-991f-845aa47a1e95/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-17%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.41.23.png" alt=""></p>
<p>일단 리스트가 한자리일 경우 바로 리스트를 반환하도록 조건문을 걸어주었다.
그리고 nums의 첫번째 인덱싱을 위해 반복문을 돌리고 그 값을 한번 더 사용하기 위해 다른 변수를 하나 더 선언해 주었다.
두번째 for문에서 첫번째 반복문보다 한자리 크게 시작하는 반복문을 구현하고 리스트의 한자리씩 전부 비교해 가장 작은 값의 인덱싱 넘버를 전에 선언해놓은 변수에 저장하였다.
마지막으로 첫번째 반복문에서 시작한 숫자와 두번째 반복문에서 가장 작은 숫자의 자리를 바꾸어 주었다.</p>
]]></description>
        </item>
    </channel>
</rss>