<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>inyong__hwang.log</title>
        <link>https://velog.io/</link>
        <description>dev_hwang의 hwang.log</description>
        <lastBuildDate>Tue, 20 Feb 2024 06:56:49 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>inyong__hwang.log</title>
            <url>https://images.velog.io/images/inyong_pang/profile/cb23e440-4169-11ea-b442-937abdb94d9c/pang.JPG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. inyong__hwang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/inyong_pang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Server] firewall-cmd service]]></title>
            <link>https://velog.io/@inyong_pang/Server-firewall-cmd-service</link>
            <guid>https://velog.io/@inyong_pang/Server-firewall-cmd-service</guid>
            <pubDate>Tue, 20 Feb 2024 06:56:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/inyong_pang/post/62e50a30-127d-42c4-a836-da34adcefa8b/image.png" alt="ipchain-netfilter-iptables-firewalld"></p>
<blockquote>
<p>Linux 커널 2.2 까지는 <code>ipchains</code> 이라는 패킷 필터링/방화벽 프레임워크가 구현되어 있었고 2.4부터는 더 유연하고 다양한 기능을 가진 <code>netfilter</code> 로 프레임워크가 교체됨</p>
</blockquote>
<blockquote>
<p><code>iptables</code>는 <code>netfilter</code> 프레임워크의 최상단 위치하는 사용자 레벨의 프로그램으로 시스템 관리자가 <code>iptables</code>명령어로 리눅스 서버나 패킬을 필터링함</p>
</blockquote>
<blockquote>
<p>그러나 <code>iptables</code>는 설정방법이 어렵고 rule(정책)적용 시 재시작을 해야하는 번거로움 존재
이에 <code>filrewall-cmd</code>(CLI), <code>firewall-config</code>(GUI)로 프로그램을 사용중</p>
</blockquote>
<h1 id="firewall-cmd-service">firewall-cmd service</h1>
<ul>
<li>CentOS7(RHEL7)부터 선보인 패킷 필터링 방화벽 프로그램</li>
<li><code>iptables</code>의 대체로 사용되고 있는 방화벽 프로그램</li>
<li><code>iptables</code>는 설정 및 변경 후 재시작해야 하지만, <code>firewalld</code>는 동적 반영 및 재시작 필요 없음
(<code>iptables</code>는 service를 재시작해야함 / <code>firewalld</code>는 <code>--reload</code> 옵션으로 재시작 가능)</li>
</ul>
<h1 id="network-zone">Network Zone</h1>
<ul>
<li>네트워크 구성의 zone(영역)을 의미하며, 해당 호스트 서버가 실제 어떤 영역에 있는지에 따라 <code>firewalld</code>를 설정을 논리적으로 zone 설정 가능</li>
</ul>
<h3 id="pre-defined-zone">pre-defined Zone</h3>
<table>
<thead>
<tr>
<th align="center">zone이름</th>
<th align="left">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">drop</td>
<td align="left">iptables에서 사용하던 Drop과 동일하며 들어오는 모든 패킷은 버려지고 이에대한 응답 메시지도 보내지 않으며 외부로 나가는 연결만 허용</td>
</tr>
<tr>
<td align="center">block</td>
<td align="left">Drop 존처럼 들어오는 모든 네트워크 연결은 거부된다. 다만 icmp-host-prohibited와 icmp6-prohibited라는 응답 메시지를 보낸다. 시스템 내부에서 시작된 연결은 허용</td>
</tr>
<tr>
<td align="center">public</td>
<td align="left">서비스를 제공하는 특별한 포트로의 연결만 허용하고, 그 외 포트로의 연결은 모두 거부, 기본 Zone으로 사용</td>
</tr>
<tr>
<td align="center">external</td>
<td align="left">특별히 매스커레이딩 규칙이 적용되는 외부의 라우터를 위해 사용되며, 내부로의 연결 요청 중 선택된 연결만을 허용(내부로 들어오는 패킷을 SSH만 제외하고 거부, 외부는 모두 허용)</td>
</tr>
<tr>
<td align="center">dmz</td>
<td align="left">내부 네트워크로의 접근은 제한적으로 허용되지만, 공개된 네트워크에 대한 접근을 허용하는 경우에 사용된다. 선택된 연결만이 허용</td>
</tr>
<tr>
<td align="center">work</td>
<td align="left">같은 회사에 위치한 네트워크를 위해 사용되며, 대부분 같은 네트워크에 위치한 다른 시스템을 신뢰하고 오직 선택된 연결만을 허용</td>
</tr>
<tr>
<td align="center">home</td>
<td align="left">홈 영역을 위해 사용되며, 네트워크에 존재하는 다른 시스템을 신뢰하고 오직 선택된 연결만을 접속 허용</td>
</tr>
<tr>
<td align="center">internal</td>
<td align="left">내부 네트워크를 위해 사용되고, 선택된 연결만을 허용</td>
</tr>
<tr>
<td align="center">trusted</td>
<td align="left">모든 네트워크 접속 연결을 허용하는 경우 사용</td>
</tr>
</tbody></table>
<h1 id="firewall-cmd-명령어-옵션">firewall-cmd 명령어 옵션</h1>
<ul>
<li><code>--state</code>                                            : firewalld 실행 상태 확인</li>
<li><code>--get-default-zone</code>                             : 현재 기본 영역 표시</li>
<li><code>--set-default-zone [zone]</code>                     : 기본 영역 설정</li>
<li><code>--get-zones</code>                                      : 사용가능한 모든 영역 나열</li>
<li><code>--get-services</code>                                    : 사용가능한 모든 서비스 나열</li>
<li><code>--get-active-zones</code>                              : 현재 사용중인 모든 영역과 인터페이스 및 소스정보 나열</li>
<li><code>--add-source=[ip주소] --zone=[zone]</code>     : 출발지 주소 규칙 추가
=&gt; &#39;--zone&#39; 옵션을 통해 zone 지정해주지 않으면 자동으로 기본영역에 추가</li>
<li><code>--remove-source=[ip주소]</code>                    : IP 주소를 지정된 영역에서 제거</li>
<li><code>--add-interface=[ifname] --zone=[zone]</code>    : 특정 영역에 interface 연결 추가</li>
<li><code>--change-interface=[ifname] --zone=[zone]</code> : 영역에 연결된 interface 변경</li>
<li><code>--list-all --zone=[zone]</code>                         : 영역에 구성된 모든 인터페이스, 소스, 서비스, 포트 나열</li>
<li><code>--add-service=[service] --zone=[zone]</code>     : 해당 서비스 트래픽 허용</li>
<li><code>--add-port=[port|protocol] --zone=[zone]</code>  : 해당 포트나 프로토콜 트래픽 허용</li>
<li><code>--permanent</code>                                : 현재 설정을 서비스가 재시작되어도 반영(영구 설정), XML파일에 저장하는 옵션</li>
<li><code>--reload</code>                                          : 런타임 구성 삭제, 영구 구성 적용</li>
<li><code>--runtime-to-permanent</code>                     : 실행중 설정을 영구 설정으로 변경</li>
</ul>
<h1 id="firewall-cmd-명령어-예제">firewall-cmd 명령어 예제</h1>
<h2 id="방화벽-서비스-가동-및-확인">방화벽 서비스 가동 및 확인</h2>
<pre><code># systemctl start firewalld.service
# systemctl status firewalld.service</code></pre><h2 id="방화벽-서비스-정지">방화벽 서비스 정지</h2>
<pre><code># systemctl stop firewalld.service</code></pre><h2 id="방화벽-서비스-자동가동-설정-및-상태-확인">방화벽 서비스 자동가동 설정 및 상태 확인</h2>
<ul>
<li>서버 재시작 시, 방화벽 서비스가 systemctl에 등록되어 있는지 확인 하는 명령어<pre><code># systemctl enable firewalld.service
# systemctl is-enabled firewalld.service
enabled</code></pre></li>
</ul>
<h2 id="방화벽-상태-확인">방화벽 상태 확인</h2>
<pre><code># firewall-cmd --state
running</code></pre><h2 id="방화벽-zone">방화벽 Zone</h2>
<h3 id="방화벽-zone-확인">방화벽 Zone 확인</h3>
<ul>
<li>현재 활성화 및 운영 중인 zone들을 확인하는 명령어</li>
<li>zone과 interface도 확인 가능<pre><code># firewall-cmd --get-active-zones
public
  interfaces eno1 eno2</code></pre></li>
<li>public zone에 interface eno1과 eno2가 할당 되어 있음</li>
</ul>
<h3 id="default-설정된-zone-확인">default 설정된 zone 확인</h3>
<pre><code># firewall-cmd --get-default-zone
public</code></pre><ul>
<li>보통의 경우 public zone이 default로 초기 설정 되어 있음</li>
</ul>
<h3 id="default-zone의-방화벽-설정-정책-확인">default zone의 방화벽 설정 정책 확인</h3>
<ul>
<li>현재 설정 확인<pre><code># firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eno1
sources:
services: dhcpv6-client http https ssh
ports: 80/tcp 443/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:</code></pre></li>
<li>영구 설정 확인<pre><code># firewall-cmd --list-all --permanent
public (active)
target: default
icmp-block-inversion: no
interfaces: eno1
sources:
services: dhcpv6-client http https ssh
ports: 80/tcp 443/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:</code></pre></li>
</ul>
<h3 id="지정-zone의-방화벽-설정-정책-확인">지정 zone의 방화벽 설정 정책 확인</h3>
<pre><code># firewall-cmd --list-all --zone=home
</code></pre><details>
<summary>명령어 결과</summary>

<pre><code>home
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcpv6-client mdns samba-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:</code></pre></details>

<h3 id="모든-zone의-방화벽-설정-정책-확인">모든 zone의 방화벽 설정 정책 확인</h3>
<pre><code># firewall-cmd --list-all-zones</code></pre><details>
<summary>명령어 결과</summary>

<pre><code>block
  target: %%REJECT%%
  icmp-block-inversion: no
  interfaces:
  sources:
  services:
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


dmz
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


drop
  target: DROP
  icmp-block-inversion: no
  interfaces:
  sources:
  services:
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


external
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: ssh
  ports:
  protocols:
  masquerade: yes
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


home
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcpv6-client mdns samba-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


internal
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcpv6-client mdns samba-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eno1
  sources:
  services: dhcpv6-client http https mysql ssh
  ports: 80/tcp 443/tcp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


trusted
  target: ACCEPT
  icmp-block-inversion: no
  interfaces:
  sources:
  services:
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:


work
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:</code></pre></details>

<h2 id="서비스-정책">서비스 정책</h2>
<h3 id="정책-등록가능한-서비스의-종류-확인">정책 등록가능한 서비스의 종류 확인</h3>
<ul>
<li><code>firewall-cmd</code>에서는 기본적으로 등록 가능한 서비스들이 있다. 등록 가능한 서비스는 다음과 같다.<pre><code># firewall-cmd --get-services
RH-Satellite-6 RH-Satellite-6-capsule amanda-client amanda-k5-client amqp amqps 
apcupsd audit bacula bacula-client bgp bitcoin bitcoin-rpc bitcoin-testnet
bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6
dhcpv6-client distcc dns docker-registry docker-swarm dropbox-lansync
elasticsearch etcd-client etcd-server finger freeipa-ldap freeipa-ldaps
freeipa-replication freeipa-trust ftp ganglia-client ganglia-master git gre
high-availability http https imap imaps ipp ipp-client ipsec irc ircs 
iscsi-target isns jenkins kadmin kerberos kibana klogin kpasswd kprop kshell
ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns
minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nfs nfs3
nmea-0183 nrpe ntp nut openvpn ovirt-imageio ovirt-storageconsole 
ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql
privoxy proxy-dhcp ptp pulseaudio puppetmaster quassel radius redis rpc-bind
rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp
smtp-submission smtps snmp snmptrap spideroak-lansync squid ssh steam-streaming
svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tftp 
tftp-client tinc tor-socks transmission-client upnp-client vdsm vnc-server
wbem-http wbem-https wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local 
xmpp-server zabbix-agent zabbix-server</code></pre></li>
</ul>
<h3 id="현재-추가된-서비스의-정책-확인">현재 추가된 서비스의 정책 확인</h3>
<ul>
<li>zone 옵션 없을 시에는 default zone으로 확인<pre><code># firewall-cmd --list-services</code></pre></li>
<li>지정 zone의 현재 서비스 확인<pre><code>firewall-cmd --list-services --zone=home</code></pre></li>
<li>지정 zone의 영구 설정된 서비스 확인<pre><code>firewall-cmd --list-services --zone=home --permanent</code></pre></li>
</ul>
<h3 id="서비스-정책-추가">서비스 정책 추가</h3>
<ul>
<li>zone 옵션 없을 시에는 default zone에 지정 서비스 추가<pre><code># firewall-cmd --add-service=http</code></pre></li>
<li>지정 zone의 지정 서비스 추가<pre><code># firewall-cmd --add-service=http --zone=home</code></pre></li>
<li>지정 zone의 영구적으로 지정 서비스 추가<pre><code># firewall-cmd --add-service=http --zone=home --permanent</code></pre></li>
<li>현 설정 적용<pre><code># firewall-cmd --reload</code></pre><h3 id="서비스-정책-삭제">서비스 정책 삭제</h3>
</li>
<li>zone 옵션 없을 시에는 default zone에 지정 서비스 삭제<pre><code># firewall-cmd --remove-service=http</code></pre></li>
<li>지정 zone의 지정 서비스 삭제<pre><code># firewall-cmd --remove-service=http --zone=home</code></pre></li>
<li>지정 zone의 영구적으로 지정 서비스 삭제<pre><code># firewall-cmd --remove-service=http --zone=home --permanent</code></pre></li>
<li>현 설정 적용<pre><code># firewall-cmd --reload</code></pre><h2 id="서비스포트-정책">서비스포트 정책</h2>
<h3 id="현재-추가된-서비스포트의-정책-확인">현재 추가된 서비스포트의 정책 확인</h3>
</li>
<li>zone 옵션 없을 시에는 default zone으로 확인<pre><code># firewall-cmd --list-ports</code></pre></li>
<li>지정 zone의 현재 서비스포트 확인<pre><code>firewall-cmd --list-ports --zone=home</code></pre></li>
<li>지정 zone의 영구 설정된 서비스포트 확인<pre><code>firewall-cmd --list-ports --zone=home --permanent</code></pre><h3 id="서비스포트-정책-추가">서비스포트 정책 추가</h3>
</li>
<li>지정 zone의 영구적으로 지정 서비스포트 추가<pre><code># firewall-cmd --add-port=8080/tcp --zone=home --permanent
# firewall-cmd --add-port=10080/udp --zone=home --permanent</code></pre></li>
<li>현 설정 적용<pre><code># firewall-cmd --reload</code></pre><h3 id="서비스포트-정책-삭제">서비스포트 정책 삭제</h3>
</li>
<li>zone 옵션 없을 시에는 default zone에 지정 서비스포트 삭제<pre><code># firewall-cmd --remove-port=8080/tcp --zone=home --permanent
# firewall-cmd --remove-port=10080/udp --zone=home --permanent</code></pre></li>
<li>현 설정 적용<pre><code># firewall-cmd --reload</code></pre></li>
</ul>
<h2 id="ip주소-정책">IP주소 정책</h2>
<h3 id="ip주소-정책-확인">IP주소 정책 확인</h3>
<pre><code># firewall-cmd --list-sources --zone=public --permanent</code></pre><h3 id="ip주소-source-추가">IP주소 Source 추가</h3>
<pre><code># firewall-cmd --add-source=192.168.0.0/24 --zone=public --permanent
# firewall-cmd --reload</code></pre><h3 id="ip주소-drop-등록">IP주소 drop 등록</h3>
<ul>
<li>drop zone에 등록되는 IP주소는 트래픽 요청이 거부된다<pre><code># firewall-cmd --add-source=192.168.11.0/24 --zone=drop --permanent
# firewall-cmd --reload</code></pre></li>
</ul>
<h3 id="등록된-ip주소-drop-zone으로-변경">등록된 IP주소 drop zone으로 변경</h3>
<pre><code># firewall-cmd --change-source=192.169.11.0/24 --zone=drop --permanent</code></pre><h3 id="지정-ip주소가-어느-zone에-할당되어-있는지-확인">지정 IP주소가 어느 zone에 할당되어 있는지 확인</h3>
<pre><code># firewall-cmd --get-zone-of-source=192.168.11.0/24</code></pre><h3 id="ip주소-정책-zone에서-삭제">IP주소 정책 zone에서 삭제</h3>
<pre><code>firewall-cmd --remove-source=192.168.11.0/24 --zone=drop --permanent</code></pre><h2 id="zone-변경">Zone 변경</h2>
<h3 id="active-zone의-변경">Active Zone의 변경</h3>
<pre><code># firewall-cmd --zome=home --change-interface=eno3 --permanent
# firewall-cmd --reload</code></pre><h3 id="default-zone-변경">default zone 변경</h3>
<pre><code># firewall-cmd --set-default-zone=home</code></pre><h2 id="custom-service">Custom Service</h2>
<h3 id="custom-service-생성">Custom Service 생성</h3>
<pre><code># firewall-cmd --permanent --new-service pang
# cat /etc/firewalld/services/pang.xml
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;service&gt;
&lt;/service&gt;</code></pre><ul>
<li>기존 xml 파일로 작성할 경우(복사-붙이기)<pre><code>firewall-cmd --permanent --new-service-from-file=[기존file.xml] --name=pang.xml</code></pre><h3 id="custom-service에-설명문-추가">Custom Service에 설명문 추가</h3>
<pre><code># firewall-cmd --permanent --service=pang --set-description=[설명문]
# firewall-cmd --permanent --service=pang --set-short=[짧은설명문]</code></pre></li>
</ul>
<h3 id="custom-service-방화벽-설정-추가">Custom Service 방화벽 설정 추가</h3>
<ul>
<li><code>pang</code>서비스에 <code>20000/tcp</code>서비스포트 허용 추가<pre><code># firewall-cmd --permanent --service=pang --add-port=20000/tcp</code></pre></li>
<li><code>pang</code>서비스에 <code>60000/udp</code>에서 <code>65000/udp</code>서비스포트 Source포트 정책 추가<pre><code># firewall-cmd --permanent --service=pang --add-source-port=60000-65000/udp</code></pre></li>
<li><code>pang</code>서비스에 <code>192.168.0.1/24</code>IP주소 Destination 정책 추가<pre><code># # firewall-cmd --permanent --service=pang --set-destination=ipv4:192.168.0.1/24</code></pre></li>
<li>현 설정 적용<pre><code># firewall-cmd --reload</code></pre><h3 id="pang-service-삭제">pang Service 삭제</h3>
<pre><code># firewall-cmd --permanent --delete-service=pang
# firewall-cmd --reload</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MySQL/MariaDB 
general_log(전역 로그)확인]]></title>
            <link>https://velog.io/@inyong_pang/MySQL-MariaDB-generallog%EC%A0%84%EC%97%AD-%EB%A1%9C%EA%B7%B8%ED%99%95%EC%9D%B8</link>
            <guid>https://velog.io/@inyong_pang/MySQL-MariaDB-generallog%EC%A0%84%EC%97%AD-%EB%A1%9C%EA%B7%B8%ED%99%95%EC%9D%B8</guid>
            <pubDate>Fri, 27 Oct 2023 05:37:17 GMT</pubDate>
            <description><![CDATA[<h1 id="mysqlmariadb의-로깅">MySQL/MariaDB의 로깅</h1>
<ul>
<li>MySQL/MariaDB에 query를 실행 할 때, connection ID와 실행 된 query 내용 그리고 그 실패/성공 여부를 확인 하고 싶을 때가 있다.</li>
<li>MySQL/MariaDB 환경에서 디버깅하기 위하여 로그를 남기고 로그를 확인 할 수 있다.</li>
<li>기본 전역로그(general_log)가 <code>OFF</code>되어 있는데, 현재 상태 값을 확인 후 임의의 log 파일로 출력하여 확인이 가능하다.</li>
</ul>
<h2 id="general_log-설정-및-파일위치-확인">general_log 설정 및 파일위치 확인</h2>
<ul>
<li>general_log 설정 확인<pre><code class="language-sql">SHOW VARIABLES LIKE &#39;general%&#39;;</code></pre>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/inyong_pang/post/95a14a73-ca95-4eca-b57f-6e4f2aa59bc1/image.png" alt="" title="VARIABLES general_log, general_log_file"></p>
<ul>
<li>general_log datadir 확인<pre><code class="language-sql">SHOW VARIABLES LIKE &#39;data%&#39;;</code></pre>
<img src="https://velog.velcdn.com/images/inyong_pang/post/f61b8cd8-cf49-4d6c-9668-2d5f210801e1/image.png" alt=""></li>
</ul>
<h2 id="general_log를-특정-파일-위치로-변경하는-방법">general_log를 특정 파일 위치로 변경하는 방법</h2>
<ul>
<li>MySQL/MariaDB 전역 초기 설정은 /etc/my.cnf.d 에서 server.cnf 또는 /etc/my.cnf 에서 설정</li>
<li>my.cnf를 확인 및 다음과 같이 수정<pre><code class="language-bash">[mariadb-10.x]
general_log=on
general_log_file=/var/lib/DBlog.log</code></pre>
</li>
<li>특정 다른 디렉토리로 옮기시에는 소유그룹이 mysql/mariadb에 있지 않으면특정 디렉토리를 접근 못 할수도 있음</li>
<li>따라서 특정 디렉토리를 미리 생성하고 소유그룹을 mysql/mariadb에 권한을 넘겨야함</li>
</ul>
<h2 id="general_log-확인-방법">general_log 확인 방법</h2>
<ul>
<li>위 general_log 설정 및 파일위치 확인 후, 해당 파일 디렉토리에서 <code>tail</code> 명령어로 Log를 실시간으로 확인<pre><code class="language-bash">sudo tail -f /var/lib/DBlog.log</code></pre>
<img src="https://velog.velcdn.com/images/inyong_pang/post/d79410e9-f78b-4060-baae-4ad1e2b6bf5d/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Devops] Docker buildx  build(at M1 Macbook)]]></title>
            <link>https://velog.io/@inyong_pang/Devops-Docker-buildx-at-M1-Macbook</link>
            <guid>https://velog.io/@inyong_pang/Devops-Docker-buildx-at-M1-Macbook</guid>
            <pubDate>Sun, 12 Sep 2021 09:32:05 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>올해 새로 MacBookPro(13-inch, M1, 2020)을 지급받아서 사용중에 있다.
근래 docker 이미지 생성, registry에 배포 및 관리 등을 하고 있는데, 
M1 MacBookPro에서 만든 이미지가 배포서버(Server)에서 pull 받아서 run하는데 문제가 발생했다.</p>
</blockquote>
<pre><code class="language-bash">WARNING: The requested image&#39;s platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
# docker logs container
standard_init_linux.go:219: exec user process caused: exec format error</code></pre>
<ul>
<li>M1의 architecture가 arm 기반으로, <code>docker build</code>로 이미지를 빌드할 시, arm64/v8 기반으로 이미지를 빌딩한다...</li>
<li>따라서 amd64 기반의 이미지를 빌드할 수 있도록 <code>docker buildx</code>(멀티 플랫폼 빌드)가 필요</li>
</ul>
<blockquote>
<p><strong>[ M1에서 만든 이미지 -&gt; x86서버에서 pull &amp; run ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/6dbda963-2e53-41c8-bb9a-a8b2c5ee57e6/image.png" alt=""></p>
</blockquote>
<blockquote>
<p><strong>[ x86서버에서 만든 이미지 -&gt; M1에서 pull &amp; run ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/1cd7f2c2-7b13-4260-aed4-b22827ace2b3/image.png" alt=""></p>
</blockquote>
<h1 id="multi-platform-docker-builds">Multi-Platform Docker Builds</h1>
<ul>
<li><a href="https://docs.docker.com/buildx/working-with-buildx/">docker-buildx</a> 는 docker images를 빌드하는데 있어 다양한 아키텍쳐를 지원</li>
<li>docker CLI 확장 플러그인으로 docker-19.03 버전 부터 사용 가능</li>
<li>별도의 Dockerfile 작성이 필요 없음</li>
<li>In-Container 드라이버 지원(Docker &amp; Kubernetes)</li>
<li>Compose 빌드 지원</li>
<li>Moby BuildKit에서 제공되는 모든 기능 지원</li>
</ul>
<h1 id="install-docker-buildx-in-m1-docker">Install docker buildx in M1-docker</h1>
<h3 id="cli-experimental-features">CLI Experimental Features</h3>
<ul>
<li>docker dashboard &gt; Preference</li>
<li>enable experiemntal features 활성화</li>
</ul>
<p><img src="https://images.velog.io/images/inyong_pang/post/37cb8376-b6b0-4c09-894a-ccd97a07e0cb/image.png" alt=""></p>
<h3 id="docker-buildx-확인">docker buildx 확인</h3>
<ul>
<li><p>활성화 전 cmd</p>
<pre><code class="language-bash">&gt; docker buildx
docker: &#39;buildx&#39; is not a docker command.</code></pre>
</li>
<li><p>활성화 후 cmd</p>
<pre><code class="language-bash">&gt; docker buildx 
ocker buildx
</code></pre>
</li>
</ul>
<p>Usage:    docker buildx COMMAND</p>
<p>Build with BuildKit</p>
<p>Management Commands:
  imagetools  Commands to work on images in registry</p>
<p>Commands:
  bake        Build from a file
  build       Start a build
  create      Create a new builder instance
  inspect     Inspect current builder instance
  ls          List builder instances
  rm          Remove a builder instance
  stop        Stop builder instance
  use         Set the current builder instance
  version     Show buildx version information</p>
<p>Run &#39;docker buildx COMMAND --help&#39; for more information on a command.</p>
<pre><code>
# docker buildx
### create builder
- 기본 builder가 모든 아키텍처를 빌드할 수 있지만, 필요한 아키텍쳐만 선택해서 또다른 builder를 생성할 수 있다

- builder ls
```bash
&gt; docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS  PLATFORMS
default * docker
  default default         running linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6</code></pre><ul>
<li>create builder    <pre><code class="language-bash">&gt; docker buildx create --name [builder instance 명] --driver [드라이버 이름] --use
</code></pre>
</li>
</ul>
<blockquote>
<p>docekr buildx create m1builder --dirver linux/arm64, linux/amd64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
-- use</p>
</blockquote>
<pre><code>- `--driver`는 여러개 복수로 지정 가능
- `--use`는 만든 builder instance를 바로 사용하는 옵션

### builder 확인
- builder inspect
```bash
&gt; docker buildx inspect m1builder --bootstrap
Name:   m1builder
Driver: docker-container

Nodes:
Name:      m1builder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Platforms: linux/arm64, linux/amd64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v

&gt; docker buildx ls
NAME/NODE    DRIVER/ENDPOINT             STATUS  PLATFORMS
m1builder *  docker-container
  m1builder0 unix:///var/run/docker.sock running linux/arm64, linux/amd64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
default      docker
  default    default                     running linux/arm64, linux/amd64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6</code></pre><h3 id="create-buildx-image">create buildx image</h3>
<ul>
<li>builder instance로 미리 작성한 Dockerfile로 image를 만듦<pre><code class="language-bash"># dockerfile 있는 디렉토리
&gt; docker buildx build --platform linux/amd64 --load --tag registry/test_api:1.0.0 .
[+] Building 36.9s (10/10) FINISHED
=&gt; [internal] load build definition from Dockerfile                                                                                                                                                                                     0.0s
=&gt; =&gt; transferring dockerfile: 32B                                                                                                                                                                                                      0.0s
=&gt; [internal] load .dockerignore                                                                                                                                                                                                        0.0s
=&gt; =&gt; transferring context: 2B                                                                                                                                                                                                          0.0s
=&gt; [internal] load metadata for docker.io/library/python:3.9.2-slim                                                                                                                                                                     3.8s
=&gt; [1/4] FROM docker.io/library/python:3.9.2-slim@sha256:ce367bb30b8928efb632c369e3bd4a8dbd7905417bd0a245087a82c250e54a24                                                                                                              14.3s
=&gt; =&gt; resolve docker.io/library/python:3.9.2-slim@sha256:ce367bb30b8928efb632c369e3bd4a8dbd7905417bd0a245087a82c250e54a24                                                                                                               0.0s
=&gt; =&gt; sha256:e083ad7cc3ca624f4e268a778cb4f8be0d7a258240144862390e0da39082ea60 2.45MB / 2.45MB                                                                                                                                           7.3s
=&gt; =&gt; sha256:65d21ac50a56640b50d18bd6c9d52bb967bd63de2e5dcce551340eb9bca26418 234B / 234B                                                                                                                                               1.5s
=&gt; =&gt; sha256:229daa3ebd94b66f007a1fce482e8f7ef6b8deaf7e75324332fdfae7a197c67c 10.89MB / 10.89MB                                                                                                                                         7.1s
=&gt; =&gt; sha256:edf8b70d3cc4282c43b24efda071ccab93b989a5dccb108b2102b0c2198c6471 2.77MB / 2.77MB                                                                                                                                           4.8s
=&gt; =&gt; sha256:75646c2fb4101d306585c9b106be1dfa7d82720baabe1c75b64d759ea8adf341 27.14MB / 27.14MB                                                                                                                                        12.9s
=&gt; =&gt; extracting sha256:75646c2fb4101d306585c9b106be1dfa7d82720baabe1c75b64d759ea8adf341                                                                                                                                                0.8s
=&gt; =&gt; extracting sha256:edf8b70d3cc4282c43b24efda071ccab93b989a5dccb108b2102b0c2198c6471                                                                                                                                                0.1s
=&gt; =&gt; extracting sha256:229daa3ebd94b66f007a1fce482e8f7ef6b8deaf7e75324332fdfae7a197c67c                                                                                                                                                0.4s
=&gt; =&gt; extracting sha256:65d21ac50a56640b50d18bd6c9d52bb967bd63de2e5dcce551340eb9bca26418                                                                                                                                                0.0s
=&gt; =&gt; extracting sha256:e083ad7cc3ca624f4e268a778cb4f8be0d7a258240144862390e0da39082ea60                                                                                                                                                0.1s
=&gt; [internal] load build context                                                                                                                                                                                                        0.0s
=&gt; =&gt; transferring context: 93B                                                                                                                                                                                                         0.0s
=&gt; [2/4] WORKDIR /home/app                                                                                                                                                                                                              0.0s
=&gt; [3/4] ADD . .                                                                                                                                                                                                                        0.0s
=&gt; [4/4] RUN pip install -r requirements.txt                                                                                                                                                                                           13.5s
=&gt; exporting to oci image format                                                                                                                                                                                                        5.1s
=&gt; =&gt; exporting layers                                                                                                                                                                                                                  1.0s
=&gt; =&gt; exporting manifest sha256:c64d4192989179c14f8e01a173e890e0856348f891db80a01c3ab9f7c124211b                                                                                                                                        0.0s
=&gt; =&gt; exporting config sha256:5ee75a529f8732c11b102ef337073268f540f539781e2c2da5c10705090d2958                                                                                                                                          0.0s
=&gt; =&gt; sending tarball</code></pre>
<ul>
<li><code>--platform</code> : builder instance가 사용가능한 platform 즉, 아키텍쳐를 선택하여 이미지를 빌드화한다.</li>
<li><code>--load</code> : 이미지를 만들고 호스트 docker image에 저장</li>
<li><code>--push</code> : <code>--load</code>옵션과 반대로 docker registry로 바로 push 하는 옵션</li>
</ul>
</li>
</ul>
<h3 id="run-image-and-check">run image and check</h3>
<ul>
<li>각각 만들어진 이미지(image)를 실행(run)하고 각 컨테이너(container)의 아키텍쳐를 확인한다</li>
<li>ex) 
  test_api:1.0.0 -&gt; docker build로 빌드화
  test_api:1.0.1 -&gt; docker buildx로 빌드화</li>
</ul>
<pre><code class="language-bash">&gt; docker images
REPOSITORY                               TAG               IMAGE ID       CREATED         SIZE
registry/test_api                  1.0.1             5ee75a529f87   3 minutes ago   125MB
registry/test_api                   1.0.0             79f4125ee89c   2 hours ago     118MB

&gt; docker run -it -d --name test_api_1.0.0 registry/test_api:1.0.0 
&gt; docker exec -it test_api_1.0.0 dpkg -s libc6 | grep Arch
Architecture: arm64
Multi-Arch: same

&gt; docker run -it -d --name test_api_1.0.1 registry/test_api:1.0.1 
&gt; docker exec -it test_api_1.0.1 dpkg -s libc6 | grep Arch
Architecture: amd64
Multi-Arch: same</code></pre>
<ul>
<li>기본 docker build로 빌드할 경우 Architecture가 m1의 아키텍처와 동일한 arm64로 빌드됨</li>
<li>docker buildx로 빌드할 경우 설정된 Architecture에 따라(amd64로 설정) 또는 --platform 에서 설정한 아키텍처에 따라 빌드됨</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ Vue.js ] Vue 가이드 - 라이프 사이클]]></title>
            <link>https://velog.io/@inyong_pang/Vue.js-Vue-%EA%B0%80%EC%9D%B4%EB%93%9C-%EB%9D%BC%EC%9D%B4%ED%94%8C-%EC%82%AC%EC%9D%B4%ED%81%B4</link>
            <guid>https://velog.io/@inyong_pang/Vue.js-Vue-%EA%B0%80%EC%9D%B4%EB%93%9C-%EB%9D%BC%EC%9D%B4%ED%94%8C-%EC%82%AC%EC%9D%B4%ED%81%B4</guid>
            <pubDate>Tue, 29 Jun 2021 08:31:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>node : v14.17.1</li>
</ul>
</blockquote>
<ul>
<li>Vue : v2</li>
<li><a href="https://kr.vuejs.org/v2/guide/">Vue.js 가이드</a>를 참고하여 작성</li>
<li>패스트캠퍼스 Vue.js 압축 완성 올인원 패키지 Online 강의 내용 참고</li>
</ul>
<hr>
<h1 id="라이프사이클lifecycle">라이프사이클(LifeCycle)</h1>
<ul>
<li>Vue 인스턴스나 컴포넌트가 생성될때, 미리 사전에 정의된 몇 단계의 과정을 거치게됨</li>
<li>이를 라이프사이클(LifeCycle)</li>
<li>Vue 인스턴스가 생성된 후 우리 눈에 보여지고 사라지기까지의 단계</li>
<li>vue.js 라이프사이클은 크게 creation, mounting, updating, destruction 로 나눠지고 각 훅(hook)으로 단계들을 실행</li>
</ul>
<p><img src="https://images.velog.io/images/inyong_pang/post/79578d0e-db9b-431b-ab07-8661e1727f93/image.png" alt=""></p>
<h2 id="creation">Creation</h2>
<ul>
<li>라이프사이클 중에서 가장 처음 실행</li>
<li>컴포넌트(Component)가 돔(DOM)에 추가되기 전</li>
<li>서버렌더링에서도 지원되는 훅(Hook)</li>
<li>따라서 클라이언트 단과 서버단 모두 처리해야하는 일이 있다면, Creation 단계에서 하면됨</li>
<li>아직 돔에 접근하거나 <code>this.$el</code>를 사용할 수 없음<h3 id="beforecreate">beforeCreate</h3>
</li>
<li>모든 훅 중 가장 먼저 실행되는 훅</li>
<li>data와 events(<code>vm.$on</code>, <code>vm.$once</code>, <code>vm.$off</code>, <code>vm.$emit</code>)가 세팅되지 않은 시점</li>
</ul>
<h3 id="created">created</h3>
<ul>
<li>data와 events가 활성화되어 접근 가능</li>
<li>하지만, 템플릿과 가상돔은 마운트(Mount) 및 렌더링되지 않은 상태.</li>
</ul>
<h2 id="mounting">Mounting</h2>
<ul>
<li>초기 렌더링 직전, 컴포넌트에 직접 접근 가능한 시점</li>
<li>서버렌더링은 지원하지 않음</li>
<li>렌더링 직전 돔을 변경하고자 할때 이 단계를 사용하여 변경 가능</li>
<li>컴포넌트 초기에 세팅되어야할 데이터 페치(fetch)는 created훅 단계를 사용하는 것이 나음</li>
<li><h3 id="beforemount">beforeMount</h3>
</li>
<li>템플릿과 렌더 함수들이 컴파일이 되고, 첫 렌더링이 일어나지 직전 시점</li>
<li>서버사이드 렌더링시에는 호출불가</li>
</ul>
<h3 id="mounted">mounted</h3>
<ul>
<li>컴포넌트, 템플릿, 렌러딩된 돔에 접근가능한 시점</li>
<li>하위 컴포넌트가 마운트된 상태를 보장하지는 않는다</li>
<li>서버렌더링에서는 호출되지 않는다</li>
<li>부모와 자식관계의 컴포넌트에서 우리가 생각한 순서대로 mounted가 발생사지 않을 수 있다
<img src="https://images.velog.io/images/inyong_pang/post/a9811ef2-549b-4d15-8cca-97c9169382fc/image.png" alt=""><h2 id="updating">Updating</h2>
</li>
<li>컴포넌트에서 사용되는 반응성 속성들이 변경되거나 어떤 이유로 재랜더링 될시 실행</li>
<li>디버깅, 프로파일링 등 컴포넌트 재랜더링 시점을 알고 싶을 때 사용</li>
<li></li>
</ul>
<h3 id="beforeupdate">beforeUpdate</h3>
<ul>
<li>컴포넌트의 데이터가 변하여 업데이트 사이클이 시작될때 실행됨</li>
<li>정확히는 돔이 재랜더링되고, 데이터를 폐치하기 전</li>
<li>재랜더링 전의 새 상태의 데이터를 얻을 수 있고, 더 많은 변경이 가능</li>
<li>이 변경으로 재랜더링은 트리거(trigger)되지 않음</li>
</ul>
<h3 id="updated">updated</h3>
<ul>
<li>컴포넌트의 데이터가 변하여 재랜더링이 일어난 후 실행</li>
<li>돔이 업데이트 완료된 상태임으로, 돔 종속적인 연산 가능</li>
<li>때에따라 상태를 변경하면 무한루프에 빠질수도 있음..모든 자식의 컴포넌트의 재랜더링 상태를 보장하지 않기 때문</li>
</ul>
<h2 id="destruction">destruction</h2>
<ul>
<li>컴포넌트가 제거 될 때 실행되는 라이프 사이클 훅<h3 id="beforedestory">beforeDestory</h3>
</li>
<li>컴포넌트가 제거 되기 직전에 호출되는 라이프 사이클 훅</li>
<li>이벤트 리스터를 해제하거나 컴포넌트에서 동작으로 할당 받은 자원들을 해제해야 할 때 적합한 훅</li>
<li>서버사이드 렌더링은 지원하지 않음</li>
</ul>
<h3 id="destory">destory</h3>
<ul>
<li>컴포넌트가 제거 된 후 호출되는 훅</li>
<li>컴포넌트의 모든 이벤트 리스터와 디렉티브의 바인딩이 해제되고, 하위 컴포넌트도 모두 제거</li>
<li>서버사이드 렌더링은 지원하지 않음</li>
</ul>
<hr>
<h1 id="example">example</h1>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;div id=&quot;app-1&quot;&gt;
        &lt;div ref=&quot;msg&quot;&gt;{{ msg }}&lt;/div&gt;
        &lt;div ref=&quot;div&quot;&gt; ref div &lt;/div&gt; &lt;!-- 참조 속성 --&gt;
&lt;/div&gt;</code></pre>
<p><strong>[ index.js ]</strong></p>
<pre><code class="language-js">const vm = new Vue({
            el: &#39;#app-1&#39;,
            data: {
                msg: &#39;Hello Vue&#39;
            },
            beforeCreate () { // 생성 전
                console.log(&#39;beforeCreate!&#39;, this.msg, this.$refs.div)
            },
            created () { // 생성
                console.log(&#39;created!&#39;, this.msg, this.$refs.div)
            },
            beforeMount () { // 마운트 업데이트 전
                console.log(&#39;beforeMount!&#39;, this.msg, this.$refs.div)
            },
            mounted () { // 마운트 업데이트
                console.log(&#39;mounted!&#39;, this.msg, this.$refs.div)
            },
            beforeUpdate () { // 반응성 데이터 업데이트 전
                console.log(&#39;beforeUpdate!&#39;, this.$refs.msg.innerText)
            },
            updated () { // 반응성 데이터 업데이트
                console.log(&#39;updated!&#39;, this.$refs.msg.innerText)
            },
            beforeDestroy () { // 반응성 제거 전
                console.log(&#39;beforeDestroy!&#39;)
            },
            destroy () { // 반응성 제거
                console.log(&#39;destroy!&#39;)
            } 
        })</code></pre>
<p><strong>[ Rendering ]</strong></p>
<ul>
<li>console log 확인</li>
<li>각 훅별 데이터와 이벤트 그리고 렌더링되는 데이터 확인</li>
<li>첫번째 값 : msg 값</li>
<li>두번째 값 : $refs.div </li>
</ul>
<p><img src="https://images.velog.io/images/inyong_pang/post/dd0608ca-09fb-4459-a0d1-562930493425/image.png" alt=""></p>
<ul>
<li>beforeCreate : data, events가 세팅되지 않았음으로 <code>undefined</code> </li>
<li>create : data, events가 세팅은 되었으나 템플릿과 가상돔은 랜더링 되지 않은 상태임으로 <code>undefined</code></li>
<li>beforeMount : data, events, 템플릿, 가상돔은 준비되었으나, 데이터가 돔에 추가되기 전임으로 <code>undefined</code></li>
<li>mounted : 컴포넌트와 돔에 데이터가 추가되어 참조속성인 <code>&lt;div&gt; ref div &lt;/div&gt;</code>가 확인됨</li>
</ul>
<p><img src="https://images.velog.io/images/inyong_pang/post/9669e64f-c1aa-4a75-88c7-c46952f0a9e5/image.png" alt=""></p>
<ul>
<li><code>vm.msg</code> 값을 &#39;new message&#39;로 변경 시, 반응성으로 돔과 실제 데이터가 변경됨</li>
<li>destory 훅을 실행 후 <code>vm.msg</code> 를 &#39;another message&#39;로 변경 시 돔의 데이터가 변경되지 않음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ Vue.js ]  Vue 가이드 - 컴포넌트 사용]]></title>
            <link>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Mon, 28 Jun 2021 08:17:15 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>node : v14.17.1</li>
</ul>
</blockquote>
<ul>
<li>Vue : v2</li>
<li><a href="https://kr.vuejs.org/v2/guide/">Vue.js 가이드</a>를 참고하여 작성</li>
</ul>
<hr>
<h1 id="컴포넌트">컴포넌트</h1>
<ul>
<li>기본 HTML 엘리먼트를 확장하여 재사용 가능한 코드를 캠슐화하는 데 사용</li>
<li>독립적으로 재사용할 수 있는 추상적 개념</li>
<li>컴포넌트로 인해 개발속도와 코드의 가독성, 유지보수성 효율적으로 늘어남</li>
<li>모든 유형의 애플리케이션 인터페이스를 컴포넌트 트리로 추상화
<img src="https://images.velog.io/images/inyong_pang/post/6841be2e-fcdf-4ec0-8ed3-6b4500bb4cd6/image.png" alt=""></li>
</ul>
<h3 id="component-예시-1">component 예시 1</h3>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;div id=&quot;app-7&quot;&gt;
  &lt;ol&gt;
    &lt;!--
      이제 각 todo-item 에 todo 객체를 제공합니다.
      화면에 나오므로, 각 항목의 컨텐츠는 동적으로 바뀔 수 있습니다.
      또한 각 구성 요소에 &quot;키&quot;를 제공해야합니다 (나중에 설명 됨).
     --&gt;
    &lt;todo-item
      v-for=&quot;item in groceryList&quot;
      v-bind:todo=&quot;item&quot;
      v-bind:key=&quot;item.id&quot;
    &gt;&lt;/todo-item&gt;
  &lt;/ol&gt;
&lt;/div&gt;</code></pre>
<p><strong>[ index.js ]</strong></p>
<pre><code class="language-js">Vue.component(&#39;todo-item&#39;, {
  props: [&#39;todo&#39;],
  template: &#39;&lt;li&gt;{{ todo.text }}&lt;/li&gt;&#39;
})

var app7 = new Vue({
  el: &#39;#app-7&#39;,
  data: {
    groceryList: [
      { id: 0, text: &#39;Vegetables&#39; },
      { id: 1, text: &#39;Cheese&#39; },
      { id: 2, text: &#39;Whatever else humans are supposed to eat&#39; }
    ]
  }
})</code></pre>
<p><strong>[ Rendering ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/8905daab-2355-4bf1-81a1-8007672aee4e/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ Vue.js ] Vue 가이드 - 사용자 입력 핸들링]]></title>
            <link>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%9E%85%EB%A0%A5-%ED%95%B8%EB%93%A4%EB%A7%81</link>
            <guid>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%9E%85%EB%A0%A5-%ED%95%B8%EB%93%A4%EB%A7%81</guid>
            <pubDate>Mon, 28 Jun 2021 07:15:24 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>node : v14.17.1</li>
</ul>
</blockquote>
<ul>
<li>Vue : v2</li>
<li><a href="https://kr.vuejs.org/v2/guide/">Vue.js 가이드</a>를 참고하여 작성</li>
</ul>
<hr>
<h1 id="사용자-입력-핸들링">사용자 입력 핸들링</h1>
<h3 id="v-on">v-on</h3>
<ul>
<li><p><a href="https://kr.vuejs.org/v2/api/index.html#v-on">v-on</a></p>
<ul>
<li>엘리먼트에 이벤트 리스너를 연결, 이벤트 유형은 전달인자로 표시</li>
<li>표현식은 메소드 이름 또는 인라인 구문, 수식어</li>
<li>수식어 <ul>
<li><code>.stop</code> : event.stopPropagation() 을 호출</li>
<li><code>.prevent</code> : event.preventDefault() 을 호출</li>
<li><code>.capture</code> : 캡처 모드에서 이벤트 리스너를 추가</li>
<li><code>.self</code>: 이벤트가 이 엘리먼트에서 전달된 경우에만 처리</li>
<li><code>.{keyCode | keyAlias}</code> : 특정 키에 대해서만 처리</li>
<li><code>.left</code> : (2.2.0) 왼쪽 버튼 마우스 이벤트 트리거 처리기</li>
<li><code>.right</code> : (2.2.0) 오른쪽 버튼 마우스 이벤트 트리거 처리기</li>
<li><code>.middle</code> : (2.2.0) 가운데 버튼 마우스 이벤트 트리거 처리기</li>
<li><code>.passive</code> : (2.3.0+) DOM 이벤트를 { passive: true }와 연결</li>
</ul>
</li>
</ul>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;div id=&quot;app-5&quot;&gt;
&lt;p&gt;{{ message }}&lt;/p&gt;
&lt;button v-on:click=&quot;reverseMessage&quot;&gt;메시지 뒤집기&lt;/button&gt;
&lt;/div&gt;</code></pre>
</li>
</ul>
<p><strong>[ index.js ]</strong></p>
<pre><code class="language-js">var app5 = new Vue({
  el: &#39;#app-5&#39;,
  data: {
    message: &#39;안녕하세요! Vue.js!&#39;
  },
  methods: {
    reverseMessage: function () {
      this.message = this.message.split(&#39;&#39;).reverse().join(&#39;&#39;)
    }
  }
})</code></pre>
<p><strong>[ Rendering ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/c82d4902-8711-4c0d-b566-7ac7584f909e/image.png" alt="">
<img src="https://images.velog.io/images/inyong_pang/post/925b9907-e3ed-441c-aae5-d6174ea38794/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ Vue.js ] Vue 가이드 - 조건문과 반복문]]></title>
            <link>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%A1%B0%EA%B1%B4%EB%AC%B8%EA%B3%BC-%EB%B0%98%EB%B3%B5%EB%AC%B8</link>
            <guid>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%A1%B0%EA%B1%B4%EB%AC%B8%EA%B3%BC-%EB%B0%98%EB%B3%B5%EB%AC%B8</guid>
            <pubDate>Mon, 28 Jun 2021 06:37:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>node : v14.17.1</li>
</ul>
</blockquote>
<ul>
<li>Vue : v2</li>
<li><a href="https://kr.vuejs.org/v2/guide/">Vue.js 가이드</a>를 참고하여 작성</li>
</ul>
<hr>
<h1 id="조건문과-반복문">조건문과 반복문</h1>
<h3 id="v-if">v-if</h3>
<ul>
<li>Vue에 삽입/업데이트/제거 등등 트랜지션 효과를 적용할 수 있는 속성</li>
<li><a href="https://kr.vuejs.org/v2/api/index.html#v-if">v-if</a><ul>
<li>표현식 값의 참 거짓을 기반으로 엘리먼트를 조건부 렌더링</li>
<li>엘리먼트 및 포함된 디렉티브 / 컴포넌트는 토글하는 동안 삭제되고 다시 작성</li>
<li>엘리먼트가 <code>&lt;template&gt;</code>엘리먼트인 경우 그 내용은 조건부 블록이 됨</li>
<li>v-if와 v-for가 같이 사용할 경우, v-for 가 우선순위가 높음(같이 사용 추천X)</li>
</ul>
</li>
</ul>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;div id=&quot;app-3&quot;&gt;
  &lt;p v-if=&quot;seen&quot;&gt;이제 나를 볼 수 있어요&lt;/p&gt;
&lt;/div&gt;</code></pre>
<p><strong>[ index.js ]</strong></p>
<pre><code class="language-js">var app3 = new Vue({
  el: &#39;#app-3&#39;,
  data: {
    seen: true
  }
})</code></pre>
<p><strong>[ Rendering ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/22411fbc-173b-4bf9-8dba-59ebb4929d9c/image.png" alt=""></p>
<h3 id="v-for">v-for</h3>
<ul>
<li><a href="https://kr.vuejs.org/v2/api/index.html#v-for">v-for</a><ul>
<li>원본 데이터를 기반으로 엘리먼트 또는 템플릿 블록에 여러번 렌더링</li>
<li>디렉티브의 값은 반복되는 현재 엘리먼트에 대한 별칭을 제공하기 위하여, 특수 구문인 <code>alias in expression</code>을 사용</li>
<li>array, object, number, string, Iterable 사용가능</li>
</ul>
</li>
</ul>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;div id=&quot;app-4&quot;&gt;
  &lt;ol&gt;
    &lt;li v-for=&quot;todo in todos&quot;&gt;
      {{ todo.text }}
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</code></pre>
<p><strong>[ index.js ]</strong></p>
<pre><code class="language-js">var app4 = new Vue({
  el: &#39;#app-4&#39;,
  data: {
    todos: [
      { text: &#39;JavaScript 배우기&#39; },
      { text: &#39;Vue 배우기&#39; },
      { text: &#39;무언가 멋진 것을 만들기&#39; }
    ]
  }
})</code></pre>
<p><strong>[ Rendering ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/7a835b7a-2db7-419f-b94f-41439472c672/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ Vue.js ] Vue 가이드 - 선언적 렌더링]]></title>
            <link>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%84%A0%EC%96%B8%EC%A0%81-%EB%A0%8C%EB%8D%94%EB%A7%81-v-bind</link>
            <guid>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%84%A0%EC%96%B8%EC%A0%81-%EB%A0%8C%EB%8D%94%EB%A7%81-v-bind</guid>
            <pubDate>Mon, 28 Jun 2021 06:25:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>node : v14.17.1</li>
</ul>
</blockquote>
<ul>
<li>Vue : v2</li>
<li><a href="https://kr.vuejs.org/v2/guide/">Vue.js 가이드</a>를 참고하여 작성</li>
</ul>
<hr>
<h1 id="선언적-렌더링">선언적 렌더링</h1>
<ul>
<li>Vue.sj의 핵심으로 간단한 템플릿 구문</li>
<li>DOM(Document Object Model)에서 데이터를 선언적으로 렌더링 할 수 있는 시스템</li>
<li>like.. flask-jinja2의 template 구문?!</li>
</ul>
<h2 id="예시">예시</h2>
<h3 id="단순한-템플릿-구문">단순한 템플릿 구문</h3>
<ul>
<li>기본적인 선언적렌더링 사용예시</li>
<li>Vue.js의 데이터를 DOM에 연결하여 렌더링</li>
</ul>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;div id=&quot;app-1&quot;&gt;
  {{ message }}
&lt;/div&gt;</code></pre>
<p><strong>[ index.js ]</strong></p>
<ul>
<li>사전에 index.js를 분기작성하여 index.html에서 import<pre><code class="language-js">var app = new Vue({
el: &#39;#app-1&#39;,
data: {
  message: &#39;안녕하세요 Vue!&#39;
}
})</code></pre>
</li>
</ul>
<p><strong>[ Rendering ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/f413c022-2726-4418-a34d-0ccf78b43054/image.png" alt=""></p>
<h3 id="v-bind">v-bind</h3>
<ul>
<li>DOM에 연결된 데이터를 Vue속성으로 반응형 페이지 만들기</li>
<li><a href="https://kr.vuejs.org/v2/api/index.html#v-bind"><code>v-bind</code></a><ul>
<li>동적으로 하나 이상의 컴포넌트 속성 또는 표현식을 바인딩</li>
<li>class또는 style 속성을 묶는 데 사용될 때, Array나 Objects와 같은 추가 값 유형을 지원</li>
<li>전달인자 없이 사용하면 속성 이름 - 값 쌍을 포함하는 객체를 바인딩 하는데 사용</li>
<li>class와 style은 Array나 Objects를 지원하지 않음</li>
</ul>
</li>
</ul>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;div id=&quot;app-2&quot;&gt;
  &lt;span v-bind:title=&quot;message&quot;&gt;
    내 위에 잠시 마우스를 올리면 동적으로 바인딩 된 title을 볼 수 있습니다!
  &lt;/span&gt;
&lt;/div&gt;</code></pre>
<p><strong>[ index.js ]</strong></p>
<pre><code class="language-js">var app2 = new Vue({
  el: &#39;#app-2&#39;,
  data: {
    message: &#39;이 페이지는 &#39; + new Date() + &#39; 에 로드 되었습니다&#39;
  }
})</code></pre>
<p><strong>[ Rendering ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/8133df49-82e0-423d-abbb-fed225871a17/image.png" alt=""></p>
<h3 id="v-model">v-model</h3>
<ul>
<li><a href="https://kr.vuejs.org/v2/api/index.html#v-model">v-model</a><ul>
<li>폼 input과 textarea 엘리먼트에 양방향 데이터 바인딩</li>
<li>Vue 인스턴스 데이터를 원본 소스로 취급</li>
<li>따라서 컴포넌트의 <code>data</code> 옵션 안에 있는 값을 초기화 선언해야함</li>
<li>더 자세한 사례는 <a href="https://kr.vuejs.org/v2/guide/forms.html">폼 입력 바인딩</a> 참고</li>
</ul>
</li>
</ul>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;div id=&quot;app-6&quot;&gt;
  &lt;p&gt;{{ message }}&lt;/p&gt;
  &lt;input v-model=&quot;message&quot;&gt;
&lt;/div&gt;</code></pre>
<p><strong>[ index.js ]</strong></p>
<pre><code class="language-js">var app6 = new Vue({
  el: &#39;#app-6&#39;,
  data: {
    message: &#39;안녕하세요 Vue!&#39;
  }
})</code></pre>
<p><strong>[ Rendering ]</strong>
<img src="https://images.velog.io/images/inyong_pang/post/0da68738-fe36-45a3-9b5d-b8106f8739e8/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ Vue.js ] Vue 가이드 - Vue 설치]]></title>
            <link>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-Vue-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@inyong_pang/Vue.js-%EA%B3%B5%EC%8B%9D%EA%B0%80%EC%9D%B4%EB%93%9C-Vue-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Mon, 28 Jun 2021 06:01:06 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>node : v14.17.1</li>
</ul>
</blockquote>
<ul>
<li>Vue : v2</li>
<li><a href="https://kr.vuejs.org/v2/guide/">Vue.js 가이드</a>를 참고하여 작성</li>
</ul>
<hr>
<h1 id="시작하기설치">시작하기(설치)</h1>
<ul>
<li>필수 환경 설치(nvm, node, npm 등등)</li>
<li>기본 <code>index.html</code>에 가이드 따라 Vue 다운로드 또는 CDN주소 import</li>
</ul>
<h2 id="vue-scirpt-추가">Vue scirpt 추가</h2>
<h3 id="버전에-따른-vuejs-파일-다운로드">버전에 따른 Vue.js 파일 다운로드</h3>
<ul>
<li><p><a href="https://kr.vuejs.org/js/vue.js">개발버전</a> : 모든 오류 메시지 및 디버그 모드</p>
</li>
<li><p><a href="https://kr.vuejs.org/js/vue.min.js">프로덕션버전</a> : 오류 메세지 없음, 33.30kb min+gzip(작은 용량으로 압축)</p>
</li>
<li><p>배포되는 환경에 따라 파일을 <code>vue.js</code> 또는 <code>vue.min.js</code>로 관리하는 것이 좋음</p>
</li>
</ul>
<h3 id="cdn">CDN</h3>
<ul>
<li>각 버전에 맞게 CDN을 통해 Vue.js 파일을 import 할 수 있음</li>
</ul>
<p><strong>[ 프로토 타이핑 또는 학습목적 ]</strong></p>
<pre><code class="language-html">&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;</code></pre>
<p><strong>[ 프로덕션 환경 ]</strong></p>
<ul>
<li>특정버전의 빌드 파일을 추가하는 것을 추천<pre><code class="language-html">&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue@2.6.0&quot;&gt;&lt;/script&gt;</code></pre>
</li>
</ul>
<p><strong>[ 기본 ES 모듈 ]</strong></p>
<ul>
<li>ES모듈을 호환하는 빌드 파일<pre><code class="language-html">&lt;script type=&quot;module&quot;&gt;
import Vue from &#39;https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.esm.browser.js&#39;
&lt;/script&gt;</code></pre>
</li>
</ul>
<p><strong>[ index.html ]</strong></p>
<pre><code class="language-html">&lt;!-- 개발버전, 도움되는 콘솔 경고를 포함. --&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue/dist/vue.js&quot;&gt;&lt;/script&gt;

&lt;!-- 또는 --&gt;

&lt;!-- 상용버전, 속도와 용량이 최적화됨. --&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vue&quot;&gt;&lt;/script&gt;</code></pre>
<h3 id="npm-install">NPM install</h3>
<ul>
<li>대규모 어플리케이션을 구축할 때에는 NPM으로 패키지를 관리한다</li>
<li>따라서 <code>vue</code> 또한 <code>npm</code>으로 관리 할 수 있다.<pre><code class="language-bash">// 최신 안정화 버전 설치
npm install vue</code></pre>
</li>
</ul>
<h3 id="clicommand-line-interface">CLI(Command Line Interface)</h3>
<ul>
<li>Vue.js에서 Vue를 빠르게 구축할 수 있도록 도와주는 <a href="https://github.com/vuejs/vue-cli">공식 CLI</a>를 지원한다.<pre><code>// 최신 vue-cli 설치
npm install i -g @vue/cl</code></pre></li>
<li>자세한 내용은 다음에..</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ JavaScript ] Node.js Install]]></title>
            <link>https://velog.io/@inyong_pang/Javascript-Node.js-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD</link>
            <guid>https://velog.io/@inyong_pang/Javascript-Node.js-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD</guid>
            <pubDate>Mon, 28 Jun 2021 04:18:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/inyong_pang/post/336651ab-49e6-4011-8586-ca9098b494d9/image.png" alt=""></p>
<blockquote>
<p><a href="https://nodejs.org/en/">Node.js</a>는 V8 이라는 구글에서 개발한 고성능 자바스크립트 엔진으로 빌드된 서버 사이드 개발용 소프트웨어 플랫폼
즉, 자바스크립트언어를 활용하여 웹 어플리키이션의 클라이언트측(Front-end), 서버측(Back-end)를 모두 개발 가능한 도구
또한 Node.js의 패키지 생태계인 <a href="https://www.npmjs.com/">npm</a>는 Node.js 설치시 기본으로 설치됨</p>
</blockquote>
<h1 id="nodejs">Node.js</h1>
<h2 id="버전">버전</h2>
<h3 id="ltslong-term-supported">LTS(Long Term Supported)</h3>
<ul>
<li>장기적으로 안정되고 신뢰도가 높은 지원이 보장되는 버전으로, 유지/보수와 보안(서버 운영등)에 초점을 맞춰 사용자에게 추천하는 버전</li>
<li>대부분 짝수(ex. 8.x.x) 버전으로 릴리즈</li>
</ul>
<h3 id="current현재-버전">Current(현재 버전)</h3>
<ul>
<li>최신 기능을 제공하고, 기존의 API의 기능 개선에 초점이 맞춰진 버전</li>
<li>업데이트가 잦고 기능이 변경될 가능성이 높음</li>
<li>대부분 홀수(ex. 9.x.x) 버전으로 릴리즈</li>
</ul>
<h2 id="npmnode-packaged-manager">NPM(Node Packaged Manager)</h2>
<ul>
<li>사용자나 개발자들이 javascript를 활용하여 만든 패키지들을 로컬환경에 공유받고 활용하고 관리할 수 있도록 만든 manager 시스템이다.</li>
<li>보통 node버전에 따라 npm이 자동으로 설치가 된다.</li>
<li>자세한 내용은 다음에...</li>
</ul>
<h3 id="packagejson">package.json</h3>
<ul>
<li>프로젝트마다 사용하난 node버전도 다르고 npm으로 설치한 패키지도 다르고 또 패키지의 버전도 각각 다르다.</li>
<li>따라서 프로젝트에 설치된 node버전과 패키지들의 버전 명세가 필요한데 이부분을 package.json에 작성되며, npm install 명령어 시, package.json</li>
</ul>
<h2 id="install">Install</h2>
<h3 id="직접-설치">직접 설치</h3>
<ul>
<li><a href="https://nodejs.org/en/">Node.js</a> 공식 홈페이지로 이동하여 운영체제(OS)에 맞는 설치 파일을 다운로드 하여 설치.</li>
</ul>
<h3 id="macos---homebrew">macOS - Homebrew</h3>
<ul>
<li>macOS용 패키지 관리 Homebrew를 이용하여 LTS 버전을 설치</li>
<li><code>brew search</code>로 설치 가능한 패키지 확인<pre><code class="language-bash">brew search node
==&gt; Formulae
libbitcoin-node    node               node-sass          node@12            node_exporter      nodeenv            ode
llnode             node-build         node@10            node@14            nodebrew           nodenv</code></pre>
</li>
<li><code>brew install node@xx</code> 으로 원하는 Major Number LTS 버전 설치<pre><code class="language-bash">brew install node@14</code></pre>
</li>
</ul>
<h3 id="ubuntu---aptadvanced-packaging-tool">ubuntu - apt(Advanced Packaging Tool)</h3>
<ul>
<li>ubuntu는 apt로 node를 설치 가능</li>
<li>특정 LTS 버전의 PPA를 가져온 후 설치</li>
<li>PPA를 가져오기 위해서는 <code>curl</code> 이 필요</li>
<li>ex) nodejs.14 LTS PPA 가져온 후 설치<pre><code class="language-bash">// update 및 필수 패키지 설치
apt update &amp;&amp; apt-get install -y build-essential curl
// nodejs.14 PPA
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
apt-get install -y nodejs</code></pre>
</li>
</ul>
<hr>
<h1 id="nvmnode-version-manager">NVM(Node Version Manager)</h1>
<ul>
<li>프로젝트가 2개 이상일 경우, 각 프로젝트마다 nodejs의 버전이 상이할 수 있다.</li>
<li>따라서, 각 프로젝트별로 nodejs의 버전을 관리하기 위해서는 NVM이 필요하다.</li>
<li>보통은 NVM설치 후 nodejs를 설치하고 nodejs 버전에 맞는 npm을 활용한다.<h2 id="install-1">Install</h2>
<h3 id="직접-설치-1">직접 설치</h3>
</li>
<li><code>curl</code>을 이용하여, 원하는 버전의 스크립트 파일을 다운로드 및 실행</li>
<li><a href="https://github.com/nvm-sh/nvm#system-version-of-node">NVM의 깃허브</a> 에서 원하는 버전(tag)를 찾아서 다운로드</li>
<li><code>source</code>명령어로 자신의 쉘 프로파일을 적용<ul>
<li>쉘프로파일은 환경에 따라 다름(bashrc, zshrc 등등)<pre><code class="language-bash">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
source ~/.bashrc</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="nvm-install-node">nvm install node</h3>
<ul>
<li><p>nvm의 설치가 완료되었으면, nvm이 설치 가능한 node 버전을 확인</p>
</li>
<li><p>참고로 엄청많음...</p>
<pre><code class="language-bash">nvm list-remote
...
v14.13.1
     v14.14.0
     v14.15.0   (LTS: Fermium)
     v14.15.1   (LTS: Fermium)
     v14.15.2   (LTS: Fermium)
     v14.15.3   (LTS: Fermium)
     v14.15.4   (Latest LTS: Fermium)
     v15.0.0
     v15.0.1
     v15.1.0
     v15.2.0
     v15.2.1
     v15.3.0
     v15.4.0
     v15.5.0
     v15.5.1
     v15.6.0
     v15.7.0
     v15.8.0
     v15.9.0
     v15.10.0
     v15.11.0
     v15.12.0
     v15.13.0
     v15.14.0
     v16.0.0
     v16.1.0
     v16.2.0
     v16.3.0
     v16.4.0
...</code></pre>
</li>
<li><p>원하는 버전 설치</p>
<pre><code class="language-bash">nvm install v14.0.15.4
// 가장 최신의 LTS 버전을 설치 하고 싶은경우
nvm install 14</code></pre>
</li>
<li><p>설치되어 있는 nvm 버전 확인
```bash
// -&gt; 현재 활성화되어 있는 버전
nvm list</p>
<pre><code>  v6.17.1</code></pre></li>
<li><blockquote>
<pre><code>v14.17.1
  v15.14.0
   v16.4.0</code></pre></blockquote>
<pre><code></code></pre></li>
</ul>
<h3 id="nvmrc">nvmrc</h3>
<ul>
<li>프로젝트마다 node 버전을 따로 관리해야할 경우가 많다</li>
<li>따라서 해당 프로젝트 디렉토리에 <code>.nvmrc</code> 라는 파일을 만들어 node 버전을 명시하고 사용하면 프로젝트별 node 버전 관리가 가능하다.</li>
</ul>
<pre><code class="language-bash">// project_01 .nvmrc
$ cat .nvmrc
v14.17.1
$ nvm use
Found &#39;/Users/inyonghwang/pang-dev/project_01/.nvmrc&#39; with version &lt;v14.17.1&gt;
$ node -v
v14.17.1
$ npm -v
6.14.13

// project_02 .nvmrc
$ cat .nvmrc
v15.14.0
$ nvm use
Found &#39;/Users/inyonghwang/pang-dev/project_02/.nvmrc&#39; with version &lt;v15.14.0&gt;
Now using node v15.14.0 (npm v7.7.6)
$ node -v
v15.14.0
$ npm -v
7.7.6</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Devops] Docker image 생성 및 실행]]></title>
            <link>https://velog.io/@inyong_pang/Devops-Make-Docker-image-and-run</link>
            <guid>https://velog.io/@inyong_pang/Devops-Make-Docker-image-and-run</guid>
            <pubDate>Sun, 23 May 2021 05:59:50 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>docker image 란 어플리케이션과 해당 환경을 패키지화한 것
docker file은 자신의 docker image를 만드는데 필요한 개발환경과 패키지등을 DSL(Domain Specific Language)화 한 것</p>
</blockquote>
<h1 id="object">object</h1>
<ul>
<li>간단하게 python-flask로 hello api를 응답해주는 application을 docker file로 image 만들어 보기</li>
<li>만든 이미지를 확인하고 실행해보기</li>
</ul>
<h1 id="create-applicationhello-api">Create Application(Hello-api)</h1>
<h3 id="development-environment">Development environment</h3>
<ul>
<li>python : v3.9.2</li>
<li>flask : v2.0.1</li>
<li>rootdir : ~/[your_path]/docker-app/api/</li>
</ul>
<h3 id="create-development-environment">Create Development environment</h3>
<pre><code class="language-bash">[1] cd ~/[your_path]/docker-app/api/
[2] virtualenv venv
[3] . venv/bin/actiavte
[4] python -m pip install --upgrade pip
[5] pip install flask gunicorn
[6] pip freeze &gt; requirements.txt</code></pre>
<p>[1] directory 변경(api path)
[2] python 가상환경 생성
[3] 가상환경 활성화
[4] pip 업그레이드
[5] flask 및 gunicorn 설치
[6] pip list를 requirements.txt 로 작성</p>
<h3 id="create-apppy">create app.py</h3>
<pre><code class="language-bash">[1] vi app.py</code></pre>
<pre><code class="language-python"># ~/docker-app/api/app.py
from flask import Flask, make_response, jsonify, request
app = Flask(__name__)

@app.route(&#39;/&#39;)
def hello():
    return jsonify({
    &#39;code&#39;: 200,
    &#39;msg&#39;: &#39;Hello World!&#39;
    })


if __name__ == &#39;__main__&#39;:
    app.run(host=&#39;0.0.0.0&#39;, port=80)
else:
    gunicorn_app = app
    gunicorn_app.debug = True</code></pre>
<ul>
<li>get 호출 시 &quot;Hello World!&quot; 응답하는 api 생성</li>
<li>gunicorn으로 실행시, &quot;app:gunicorn_app&quot; parameter로 넘겨서 실행해야함</li>
<li>ex) gunicorn -b 0:8080 app:gunicorn_app</li>
<li>gunicorn 사용법은 다음 포스트에...</li>
</ul>
<h3 id="flask-run-server">flask run server</h3>
<pre><code class="language-bash">[1] python app.py
* Serving Flask app &#39;app&#39; (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on all addresses.
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://172.30.82.223:80/ (Press CTRL+C to quit)</code></pre>
<h3 id="http-request--response">http request &amp; response</h3>
<pre><code class="language-bash">[1] curl -v localhost
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 80 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
&gt; GET / HTTP/1.1
&gt; Host: localhost
&gt; User-Agent: curl/7.64.1
&gt; Accept: */*
&gt;
* HTTP 1.0, assume close after body
&lt; HTTP/1.0 200 OK
&lt; Content-Type: application/json
&lt; Content-Length: 34
&lt; Server: Werkzeug/2.0.1 Python/3.9.2
&lt; Date: Sun, 23 May 2021 04:16:33 GMT
&lt;
{&quot;code&quot;:200,&quot;msg&quot;:&quot;Hello World!&quot;}
* Closing connection 0</code></pre>
<ul>
<li>client에서 curl로 http request 및 response 확인</li>
</ul>
<h1 id="create-dockerfile">Create DockerFile</h1>
<h3 id="vi-dockerfile">vi Dockerfile</h3>
<pre><code class="language-bash">vi Dockerfile</code></pre>
<ul>
<li>위 application을 ubuntu기반으로 dockerfile 작성</li>
</ul>
<pre><code class="language-bash"># api/Dockerfile
[1] FROM ubuntu:20.04
[2] WORKDIR /home/docker-app/api
[3] RUN apt update &amp;&amp; apt-get install python3 python3-pip -y
[4] ADD . .
[5] RUN pip3 install -r requirements.txt
[6] EXPOSE 8080
[7] CMD gunicorn -b 0:8080 --access-logfile log/access.log --error-logfile log/error.log --threads 4 app:gunicorn_app</code></pre>
<ul>
<li>Dockerfile 내 내용은 각 옵션에 따라 Docker Container 내에서 실행된다.</li>
</ul>
<p>[1] <code>FROM</code> 은 docker container의 운영체제를 지정함
또는 빌드환경을 지정함
[2] <code>WORKDIR</code> docker container 내 해당 application project main directory를 지정하여 만들고 이동함
[3] <code>RUN</code> docker container 내에서 실행하는 명령어로 container의 OS가 ubuntu로 지정하였음으로 <code>apt</code> 명령어로 업데이트 및 python3를 설치
(정확하게 위 api 와 같이 python v3.9.2 버전을 설치하고자 한다면, wget으로 별도로 설치해야함.)</p>
<p>[4] <code>ADD</code> 현재 host(내 PC)의 directory의 파일들을 container의 directory로 추가 (현재 ~/api/ 디렉토리에 api의 파일들(app.py, requirements.txt 등)을 container의 workdir로 이동 또는 directory를 지정가능 ex) ADD . /home/docker-app/api)</p>
<p>[5] (ubuntu에는 기본 python2가 설치 되어 있음으로..) pip3 로 requirements.txt 파일을 읽어서 application에 필요한 패키지 설치
[6] <code>EXPOSE</code> 는 container의 service port를 설정하는 것으로 <code>8080</code>포트를 열어줌
[7] <code>CMD</code>는 container 초기 구동 시 실행되는 명령어로 <code>gunicorn</code> 명령어로 프로젝트를 실행할 수 있는 명령어를 작성</p>
<h1 id="create-docker-image">create docker image</h1>
<h3 id="docker-build">docker build</h3>
<pre><code class="language-bash">docker build --tag docker-app/api:1.0.0 .
[+] Building 283.9s (10/10) FINISHED
 =&gt; [internal] load build definition from Dockerfile                                                                                                                                                                                     0.0s
 =&gt; =&gt; transferring dockerfile: 765B                                                                                                                                                                                                     0.0s
 =&gt; [internal] load .dockerignore                                                                                                                                                                                                        0.0s
 =&gt; =&gt; transferring context: 2B                                                                                                                                                                                                          0.0s
 =&gt; [internal] load metadata for docker.io/library/ubuntu:20.04                                                                                                                                                                          1.2s
 =&gt; [1/5] FROM docker.io/library/ubuntu:20.04@sha256:cf31af331f38d1d7158470e095b132acd126a7180a54f263d386da88eb681d93                                                                                                                    0.0s
 =&gt; [internal] load build context                                                                                                                                                                                                        0.1s
 =&gt; =&gt; transferring context: 134.83kB                                                                                                                                                                                                    0.1s
 =&gt; CACHED [2/5] WORKDIR /home/docker-app/api                                                                                                                                                                                            0.0s
 =&gt; [3/5] RUN apt update &amp;&amp; apt-get install -y  build-essential  zlib1g-dev  libncurses5-dev  libgdbm-dev  libnss3-dev  libssl-dev  libreadline-dev  libffi-dev  libsqlite3-dev  wget  libbz2-dev &amp;&amp; wget https://www.python.org/ftp/  268.6s
 =&gt; [4/5] ADD . .                                                                                                                                                                                                                        0.4s
 =&gt; [5/5] RUN pip3 install -r requirements.txt                                                                                                                                                                                          10.1s
 =&gt; exporting to image                                                                                                                                                                                                                   3.5s
 =&gt; =&gt; exporting layers                                                                                                                                                                                                                  3.5s
 =&gt; =&gt; writing image sha256:902f310dd3ccf93901bd9398f964f46d1fe7ecde67eab676468517ea8a79cc17                                                                                                                                             0.0s
 =&gt; =&gt; naming to docker.io/docker-app/api:1.0.0
</code></pre>
<ul>
<li><p>작성한 dockerfile 기준으로 docker image를 만듬</p>
</li>
<li><p><code>build</code> : docker image를 만들때 사용하는 옵션</p>
<ul>
<li><code>--tag</code> : tag를 달아서 이미지를 만들수 있음
  ex) [project이름]/[어플리케이션이름]:[버전]</li>
</ul>
</li>
<li><p><code>.</code> : Dockerfile의 위치를 옵션으로 넣어줌(현재는 ~/api/ 에 Dockerfile를 작성하고 docker build 명령어를 실행하기에 현재 디렉토리(<code>.</code>)로 옵션을 넣음)</p>
</li>
</ul>
<h3 id="docker-images">docker images</h3>
<pre><code class="language-bash">docker images
(venv) ➜  api docker images
REPOSITORY                              TAG       IMAGE ID       CREATED          SIZE
docker-app/api                          1.0.0     902f310dd3cc   12 minutes ago   1.06GB</code></pre>
<ul>
<li><code>docker images</code> 명령어를 통해 현재 만들어진 docker image를 확인</li>
</ul>
<h1 id="docker-run">docker run</h1>
<h3 id="docker-running">docker running</h3>
<pre><code class="language-bash">docker run -d -p 8080:8080 --name test-api docker-app/api:1.0.0
423b00d6a09f7b8f626b6054cf53dcb73ed2c57ee0c6e0fb85dc6aab026d9198</code></pre>
<ul>
<li>생성한 docker images를 <code>docker run</code> 명령어로 실행</li>
<li><code>-d</code> : daemon processor로 구동</li>
<li><code>-p</code> : local에서 docker-container로 port forwarding 하는 옵션으로, local포트(8080)을 container포트(8080)으로 매핑하는 것
ex) <code>-p 80:8080</code> 이면 local포트(80)을 container포트(8080)으로 매핑</li>
<li><code>--name</code> : container의 이름(별칭)을 지어줌</li>
<li><code>[image_name]</code> : 마지막으로 local에 해당되는 이미지가 있으면 가져와서 실행. 또는 docker-hub(또는 docker registry가 될수도 있음) 에서 image이름에 맞는 image를 pull 받아서 실행.</li>
</ul>
<h3 id="docker-ps--docker-ps--a">docker ps | docker ps -a</h3>
<pre><code class="language-bash">docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS          PORTS                    NAMES
423b00d6a09f   docker-app/api:1.0.0   &quot;/bin/sh -c &#39;gunicor…&quot;   24 minutes ago   Up 24 minutes   0.0.0.0:8080-&gt;8080/tcp   test-api

docker ps -a
CONTAINER ID   IMAGE                                         COMMAND                  CREATED          STATUS                      PORTS                    NAMES
423b00d6a09f   docker-app/api:1.0.0                          &quot;/bin/sh -c &#39;gunicor…&quot;   24 minutes ago   Up 24 minutes               0.0.0.0:8080-&gt;8080/tcp   test-api
9e3012c16905   xxx.xxx.xxx/test_api:1.0.0    &quot;gunicorn -b 0:8080 …&quot;   11 days ago      Exited (0) 40 minutes ago                            api</code></pre>
<ul>
<li><code>docker ps</code> : 현재 구동중인 docker container의 process 이름, 상태, CMD등 정보를 출력</li>
<li><code>docker ps -a</code> : <code>-a</code>를 추가 옵션을 넣을 경우, 구동중이거나 멈춰있거나 모든 상태의 docker container 정보를 출력</li>
</ul>
<h3 id="http-request--response-1">http request &amp; response</h3>
<pre><code class="language-bash">curl -v localhost:8080
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
&gt; GET / HTTP/1.1
&gt; Host: localhost:8080
&gt; User-Agent: curl/7.64.1
&gt; Accept: */*
&gt;
&lt; HTTP/1.1 200 OK
&lt; Server: gunicorn
&lt; Date: Sun, 23 May 2021 06:01:16 GMT
&lt; Connection: keep-alive
&lt; Content-Type: application/json
&lt; Content-Length: 44
&lt;
{
  &quot;code&quot;: 200,
  &quot;msg&quot;: &quot;Hello World!&quot;
}
* Connection #0 to host localhost left intact
* Closing connection 0</code></pre>
<hr>
<h1 id="참고-dockerfile-with-python-v39xx특정버전">[참고] dockerfile with python v3.9.xx(특정버전)</h1>
<h2 id="python-39xx특정버전-수동설치">python 3.9.xx(특정버전) 수동설치</h2>
<ul>
<li>특정 python 버전으로 dockerfile을 만들고자 한다면, 특정 버전의 python을 wget으로 받아서 설치해야한다.<pre><code class="language-bash"># dockerfile
FROM ubuntu:20.04
WORKDIR /home/docker-app/api
[1]RUN apt update \
&amp;&amp; apt-get install -y \
  build-essential \
  zlib1g-dev \
  libncurses5-dev \
  libgdbm-dev \
  libnss3-dev \
  libssl-dev \
  libreadline-dev \
  libffi-dev \
  libsqlite3-dev \
  wget \
  libbz2-dev \
[2]&amp;&amp; wget https://www.python.org/ftp/python/3.9.2/Python-3.9.2.tgz \
[3]&amp;&amp; tar -xf Python-3.9.2.tgz \
[4]&amp;&amp; cd Python-3.9.2 \
[5]&amp;&amp; ./configure --enable-optimizations \
[6]&amp;&amp; make -j 12 &amp;&amp; make altinstall \
[7] update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.9 1
[8]&amp;&amp; apt-get install -y python3-pip
ADD . .
RUN pip3 install -r requirements.txt
EXPOSE 8080
CMD gunicorn -b 0:8080 --access-logfile log/access.log --error-logfile log/error.log --threads 4 app:gunicorn_app</code></pre>
[1] python 설치관련 필요한 패키지를 <code>apt-get</code>으로 설치
[2] <code>wget</code>으로 공식 python v3.9.2 repository의 파일들을 다운로드
[3] <code>Python-3.9.2.tgz</code> 압축해제
[4] <code>Python-3.9.2</code> 디렉토리 이동
[5] 설치 config 설정
[6] <code>make</code> 명령어로 컴파일 및 설치
[7] <code>python3.9</code>를 <code>python3</code> 링크로 업데이트
[8] <code>python3-pip</code> 설치</li>
</ul>
<h2 id="python392-slim">python:3.9.2-slim</h2>
<ul>
<li>어느날 리서치해보니 수많은 docker hub 들 중 <a href="https://hub.docker.com/_/python">python - docker hub</a>를 찾았다.</li>
<li>그 중 docker image를 light하게 python을 구동할 수 있는 image를 찾았다.<pre><code class="language-bash">[1]FROM python:3.9.2-slim
WORKDIR /home/docker-app/api
ADD . .
[2]RUN pip install -r requirements.txt
EXPOSE 8080
CMD gunicorn -b 0:8080 --access-logfile log/access.log --error-logfile log/error.log --threads 4 app:gunicorn_app</code></pre>
[1] python-docker hub에서 원하는 버전의 <code>slim</code> 태그 버전을 선택하여 설치
[2] 기존에는 python3를 별도로 설치했어야했지만, pip가 버전에 맞게 설치되어 있음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Devops] Docker 설치 in linux]]></title>
            <link>https://velog.io/@inyong_pang/Devops-Docker-%EC%84%A4%EC%B9%98-in-linux</link>
            <guid>https://velog.io/@inyong_pang/Devops-Docker-%EC%84%A4%EC%B9%98-in-linux</guid>
            <pubDate>Fri, 02 Apr 2021 02:00:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>linux 계열에서 ubuntu 기준으로 docker를 설치하고자한다.</p>
</blockquote>
<h1 id="docker-설치-in-linuxubuntu">Docker 설치 in linux(ubuntu)</h1>
<h3 id="1-최신-패키지-리스트-업데이트">1. 최신 패키지 리스트 업데이트</h3>
<pre><code class="language-bash">sudo apt update</code></pre>
<h3 id="2-docker-다운로드를-위한-필수-패키지-다운로드">2. docker 다운로드를 위한 필수 패키지 다운로드</h3>
<pre><code class="language-bash">sudo apt install apt-transport-https ca-certificates curl software-properties-common</code></pre>
<h3 id="3-docker-repository-gpg-key-설정">3. docker repository GPG key 설정</h3>
<pre><code class="language-bash">curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -</code></pre>
<h3 id="4-docker-repository-등록">4. docker repository 등록</h3>
<pre><code class="language-bash">sudo add-apt-repository &quot;deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable&quot;</code></pre>
<h3 id="5-등록한-docker-repository까지-포함하여-최신-패키지-리스트-업데이트">5. 등록한 docker repository까지 포함하여 최신 패키지 리스트 업데이트</h3>
<pre><code class="language-bash">sudo apt update</code></pre>
<h3 id="6-docker-설치">6. docker 설치</h3>
<pre><code class="language-bash">sudo apt install docker-ce</code></pre>
<h3 id="7-docker-service-확인">7. docker service 확인</h3>
<pre><code class="language-bash">sudo systemctl status docker</code></pre>
<h1 id="sudo-명령어없이-docker-실행하기">sudo 명령어없이 docker 실행하기</h1>
<h3 id="1-현-사용자-계정을-docker-group에-등록">1. 현 사용자 계정을 docker group에 등록</h3>
<pre><code class="language-bash">sudo usermod -aG docker ${USER}</code></pre>
<h3 id="2-재접속">2. 재접속</h3>
<h3 id="3-현-계정의-group-확인">3. 현 계정의 group 확인</h3>
<pre><code class="language-bash">id -nG

ubuntu adm dialout cdrom floppy sudo audio dip video plugdev netdev lxd docker</code></pre>
<h3 id="4-sudo없이-docker-맘대로-사용">4. sudo없이 docker 맘대로 사용</h3>
<h1 id="docker-compose-설치">docker-compose 설치</h1>
<h3 id="1-release-page에서-최신-버전-확인">1. release page에서 최신 버전 확인</h3>
<p><a href="https://docs.docker.com/compose/release-notes/">docker compose release notes</a></p>
<ul>
<li>확인된 버전 : 1.28.6(2021-03-23 release)</li>
</ul>
<h3 id="2-docker-compose-다운">2. docker-compose 다운</h3>
<ul>
<li>curl을 이용하여 docker github에서 위 확인된 버전으로 다운 및 로컬 시스템 디렉토리(usr/local/bin/docker-compose)에 저장<pre><code class="language-bash">sudo curl -L https://github.com/docker/compose/releases/download/1.28.6/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose</code></pre>
</li>
</ul>
<h3 id="3-실행-권한-주기">3. 실행 권한 주기</h3>
<pre><code class="language-bash">sudo chmod +x /usr/local/bin/docker-compose</code></pre>
<h3 id="4-docker-compose-실행-확인">4. docker-compose 실행 확인</h3>
<pre><code class="language-bash">docker-compose --version

docker-compose version 1.28.6</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Programming] 암호화 알고리즘 종류와 분류]]></title>
            <link>https://velog.io/@inyong_pang/Programming-%EC%95%94%ED%98%B8%ED%99%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A2%85%EB%A5%98%EC%99%80-%EB%B6%84%EB%A5%98</link>
            <guid>https://velog.io/@inyong_pang/Programming-%EC%95%94%ED%98%B8%ED%99%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A2%85%EB%A5%98%EC%99%80-%EB%B6%84%EB%A5%98</guid>
            <pubDate>Wed, 31 Mar 2021 02:50:05 GMT</pubDate>
            <description><![CDATA[<h1 id="정의">정의</h1>
<ul>
<li>평문(Plaintext) : 해독 가능한 형태의 메시지(암호화전 메시지)</li>
<li>암호문(Cipertext) : 해독 불가능한 형태의 메시지(암호화된 메시지</li>
<li>암호화(Encryption) : 평문을 암호문으로 변환하는 과정</li>
<li>복호화(Decryption) : 암호문을 평문으로 변환하는 과정</li>
<li>전자서명<ul>
<li>송신자의 Private Key로 메시지를 서명하여 전달</li>
<li>수신자측에서는 송신자의 Public Key를 이용하여 서명값을 검증</li>
</ul>
</li>
<li>양방향암호화 : 암호화와 복호화과정을 통해 송.수신간 주고받는 메시지를 안전하게 암.복호화하는 과정</li>
<li>단방향암호화 : 해싱(Hashing)을 이용한 암호화 방식으로 양방향과는 다른 개념으로, 평문을 암호문으로 암호화는 가능하지만 암호문을 평문으로 복호화 하는 것은 불가능.
<img src="https://images.velog.io/images/inyong_pang/post/ff516b31-dddc-498c-a43b-59d3f9600d92/image.png" alt=""></li>
</ul>
<h1 id="양방향-암호화대칭비대칭-키">양방향 암호화(대칭/비대칭 키)</h1>
<ul>
<li>대칭키 : 같은 키를 이용하여 메시지를 암.복호화 하는 것</li>
<li>비대칭키 : 메시지를 암호화 하는 키와 복호화 하는 키가 다름<ul>
<li>암호화 알고리즘에 따라 사용방식이 다를수도 있다</li>
<li>전자서명을 위한 알고리즘에서는 Private Key로 메시지를 서명하고, Public Key로 검증</li>
<li>메시지 교환에서는 Public Key로 메시지를 암호화하고 Private Key로 복호화한다.
<img src="https://images.velog.io/images/inyong_pang/post/70aa687b-de53-44c4-982a-6e7bcd26e221/image.png" alt=""></li>
</ul>
</li>
</ul>
<h2 id="대칭키-암호화">대칭키 암호화</h2>
<ul>
<li>종류 : AES128, AES256, SEED(국내표준)</li>
<li>암.복호화 키가 같음</li>
<li>문제점은 수신측에 키를 전달하는 과정에서 유출될 우려가 있음</li>
<li>스트림기반, 블록기반의 암호화로 나눌수 있음
<img src="https://images.velog.io/images/inyong_pang/post/a4f69214-9af9-4e6e-80bd-3c9d8452c5b1/image.png" alt=""></li>
</ul>
<h3 id="스트림기반-암호화">스트림기반 암호화</h3>
<ul>
<li>비트단위로 암호화하는 방식.</li>
<li>LFFSR, MUX generator 등의 스트림기반 암호화 알고리즘</li>
<li>속도가 빠르고 오류 전파 현상이 없다는 장점</li>
<li>주로 오디오/비디오 스트리밍 시 사용
<img src="https://images.velog.io/images/inyong_pang/post/66538238-a58e-40c8-9d37-f0bb8792dc44/image.png" alt=""></li>
</ul>
<h3 id="블록기반-암호화">블록기반 암호화</h3>
<ul>
<li>블록 단위로 암호화를 수행하는 방식</li>
<li>문자열 단어 하나하나를 블록으로 나누어 암호화하는 과정</li>
<li>DES, AES, IDEA, SEED 등의 블록기반 암호화 알고리즘
<img src="https://images.velog.io/images/inyong_pang/post/4a894f60-5d61-4eb8-b505-2714620be139/image.png" alt=""></li>
</ul>
<h2 id="비대칭키-암호화">비대칭키 암호화</h2>
<ul>
<li>종류 : DSA(전자서명), RSA(메시지 암.복호화)</li>
<li>대칭키에 비해서는 느리다는 단점이 있음</li>
<li>키생성시 Private Key와 Public Key 2개의 키가 도출되며, Public Key는 공개해도 문제가 되지 않는다.</li>
<li>인수분해, 이산대수, 타원곡선 암호화로 나뉨
<img src="https://images.velog.io/images/inyong_pang/post/6264de1f-8267-434c-9498-5a2a5a4d728e/image.png" alt=""><h3 id="eccelliptic-curve-cryptography">ECC(Elliptic Curve Cryptography)</h3>
</li>
<li>타원곡선 암호화로써 RSA에 비해 짧은 길이의 키를 사용하면서도 비슷한 수준의 안정성을 제공</li>
<li>비트코인 및 이더리움에서 ECC알고리즘을 이용<h3 id="ecc-기반의-암호화">ECC 기반의 암호화</h3>
</li>
<li>ECDSA(Elliptic Curve Digital Signature Algorithm)
  : 전자서명(ECC 암호화 알고리즘을 전자서명에 사용한 것)</li>
<li>ECDH(Elliptic Curve Diff-Hellman)
  : 키교환 알고리즘(자신의 Private Key와 상대방의 Public Key를 사용하여 공통된 Secret 키를 도출)</li>
<li>ECIES(Elliptic Curve Integreated Encryption Scheme)
  : 통합 암호화 방식(Public Key로 암호화하고 Private Key로 복호화)</li>
</ul>
<hr>
<h1 id="단방향-암호화">단방향 암호화</h1>
<ul>
<li><p>Hash를 이용하여 암호화하는 과정</p>
</li>
<li><p>평문을 암호화할순 있지만, 복호화는 불가능하다</p>
</li>
<li><p>데이터의 진위여부는 확인하고 싶으나, 본 데이터의 Privacy를 지키고 싶은 경우 사용</p>
</li>
<li><p>ex) Bcrypt-JWT (참고:<a href="https://velog.io/@inyong_pang/%EC%9D%B8%EC%A6%9DAuthentication-%EC%9D%B8%EA%B0%80Authorization-xck5qfasw4">인증(Authentication) &amp; 인가(Authorization)</a>)</p>
</li>
<li><p>hash할 때, hash 값은 크기와 알고리즘에 따라 암호문의 결과가 완전 상이함</p>
</li>
</ul>
<h3 id="단방향-hash-알고리즘">단방향 Hash 알고리즘</h3>
<p>| 알고리즘분류 | 알고리즘명 | MD 길이 | 블록 길이 | 최대 메시지 길이 |  |
|:---:|:---:|:---:|:---:|:---:|
| MD5 | MD5 | 128bit | 512bit | 무한 |
| RIPEMD | RIPEMD-160 | 160bit | 512bit | 2^64-1bit |
| SHA-1 | SHA-1 | 160bit | 512bit | 2^64-1bit |
| SHA-2 | SHA-224 | 224bit | 512bit | 2^64-1bit |
| SHA-2 | SHA-256 | 256bit | 512bit | 2^64-1bit |
| SHA-2 | SHA-384 | 384bit | 1024bit | 2^128-1bit |
| SHA-2 | SHA-512 | 512bit | 1024bit | 2^128-1bit |
| SHA-3 | SHA-2와 디자인이 달리짐 |</p>
<ul>
<li><p><a href="https://ko.wikipedia.org/wiki/SHA-3">SHA-3</a></p>
</li>
<li><p>참고</p>
<table>
<thead>
<tr>
<th align="center">알고리즘</th>
<th align="center">해시값 크기</th>
<th align="center">내부 상태 크기</th>
<th align="center">블록 크기</th>
<th align="center">길이 한계</th>
<th align="center">워드 크기</th>
<th align="center">과정수</th>
<th align="center">사용되는 연산</th>
<th align="center">충돌</th>
</tr>
</thead>
<tbody><tr>
<td align="center">SHA-0</td>
<td align="center">160</td>
<td align="center">160</td>
<td align="center">512</td>
<td align="center">64</td>
<td align="center">32</td>
<td align="center">80</td>
<td align="center">+,and,or,xor,rotl</td>
<td align="center">발견됨</td>
</tr>
<tr>
<td align="center">SHA-1</td>
<td align="center">160</td>
<td align="center">160</td>
<td align="center">512</td>
<td align="center">64</td>
<td align="center">32</td>
<td align="center">80</td>
<td align="center">+,and,or,xor,rotl</td>
<td align="center">발견됨</td>
</tr>
<tr>
<td align="center">SHA-256/224</td>
<td align="center">256/224</td>
<td align="center">256</td>
<td align="center">512</td>
<td align="center">64</td>
<td align="center">32</td>
<td align="center">64</td>
<td align="center">+,and,or,xor,shr,rotr</td>
<td align="center">-</td>
</tr>
<tr>
<td align="center">SHA-512/384</td>
<td align="center">512/384</td>
<td align="center">512</td>
<td align="center">1024</td>
<td align="center">128</td>
<td align="center">64</td>
<td align="center">80</td>
<td align="center">+,and,or,xor,shr,rotr</td>
<td align="center">-</td>
</tr>
</tbody></table>
</li>
</ul>
<h1 id="reference">Reference</h1>
<ul>
<li><a href="https://www.kisa.or.kr/jsp/common/downloadAction.jsp?bno=259&amp;dno=82&amp;fseq=1">https://www.kisa.or.kr/jsp/common/downloadAction.jsp?bno=259&amp;dno=82&amp;fseq=1</a></li>
<li><a href="https://alexonepath.github.io/category/etc/etc-crypto.html#">https://alexonepath.github.io/category/etc/etc-crypto.html#</a></li>
<li><a href="https://jusungpark.tistory.com/34">https://jusungpark.tistory.com/34</a></li>
<li><a href="https://javaplant.tistory.com/26">https://javaplant.tistory.com/26</a></li>
<li><a href="https://www.twilio.com/blog/what-is-public-key-cryptography">https://www.twilio.com/blog/what-is-public-key-cryptography</a></li>
<li><a href="https://m.blog.naver.com/PostView.nhn?blogId=jvioonpe&amp;logNo=220703730770&amp;proxyReferer=https:%2F%2Fwww.google.com%2F">https://m.blog.naver.com/PostView.nhn?blogId=jvioonpe&amp;logNo=220703730770&amp;proxyReferer=https:%2F%2Fwww.google.com%2F</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MacOS] 환경변수 초기화]]></title>
            <link>https://velog.io/@inyong_pang/MAC-%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98-%EC%B4%88%EA%B8%B0%ED%99%94</link>
            <guid>https://velog.io/@inyong_pang/MAC-%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98-%EC%B4%88%EA%B8%B0%ED%99%94</guid>
            <pubDate>Tue, 30 Mar 2021 00:48:43 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>한 로컬내에서 이것저것 삽집하던 중에 환경변수에 여러가지 변수들이 혼잡해 있는 것을 확인하였다.
속도가 느려지거나 실행이 안되는것이 없지만, 뭔지 알수없는 이 찜찜함을 씻어내기위해(?)
MAC os의 환경변수를 확인하고 환경변수를 초기화하는 과정을 알아보았다.</p>
</blockquote>
<hr>
<h1 id="what-the-환경변수">What the 환경변수?</h1>
<blockquote>
<p>환경변수 란 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치는 동적인 값들의 모임.</p>
</blockquote>
<p>예를들어 운영체제에서 흔히 실행하는 모든 작업창(IDE, 웹브라우져, 슬랙, 카톡, 등등)들은 엄밀히 이야기하면, 프로세스들은 전부 OS라는 프로그램에 의해 실행되는 자식 프로세스들이다.
(응용Application에서 만들어내는 자식 프로세스와는 다른 개념)
바로 이때, OS입장에서 해당 프로세스를 실행시키기 위해 참조하는 변수가 <strong>환경변수</strong> 이다.</p>
<p>따라서 어떤 프로그램을 실행시키는데 있어서 그 프로그램의 실행경로들을 환경변수로 설정하는 경우가 많다.
또는 웹어플리케이션의 특성을 설정하는데 활용하기도한다. ex) ENV=dev(개발서버) | ENV=prod(상용서버)</p>
<h1 id="mac에서-환경변수-확인">MAC에서 환경변수 확인</h1>
<ul>
<li>환경변수 전체 확인 </li>
</ul>
<pre><code class="language-bash">env(또는 printenv)</code></pre>
<ul>
<li>PATH 만 확인<pre><code class="language-bash">env | grep PATH</code></pre>
</li>
</ul>
<h1 id="환경변수-초기화">환경변수 초기화</h1>
<ol>
<li>뭔지모르겠음111(아시는 분 댓글 부탁111)</li>
</ol>
<pre><code class="language-bash">defaults write com.apple.finder AppleShowAllFiles YES</code></pre>
<ol start="2">
<li><p>open bash_profile 없을 경우 create bash_profile</p>
<pre><code class="language-bash">vi ~/.bash_profile</code></pre>
</li>
<li><p>edit like text and paste it there</p>
<pre><code class="language-bash">PATH=/usr/bin:/bin:/usr/sbin:/sbin   
export PATH  
PATH=/usr/local/bin:/usr/local/sbin:&quot;$PATH&quot;  
PATH=/opt/local/bin:/opt/local/sbin:&quot;$PATH&quot;</code></pre>
</li>
<li><p>뭔지모르겠음222(아시는 분 댓글 부탁222)</p>
<pre><code class="language-bash">defaults write com.apple.finder AppleShowAllFiles NO</code></pre>
</li>
</ol>
<h3 id="reference">Reference</h3>
<ul>
<li><a href="https://life-of-panda.tistory.com/41">https://life-of-panda.tistory.com/41</a></li>
<li><a href="https://apple.stackexchange.com/questions/216125/how-can-i-reset-path-in-osx">https://apple.stackexchange.com/questions/216125/how-can-i-reset-path-in-osx</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] MySQL5.7 설치 in ubuntu]]></title>
            <link>https://velog.io/@inyong_pang/mysql-ubuntu-mysql-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@inyong_pang/mysql-ubuntu-mysql-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Tue, 23 Feb 2021 07:25:09 GMT</pubDate>
            <description><![CDATA[<h1 id="1-ubuntu-버전-확인">1. ubuntu 버전 확인</h1>
<pre><code class="language-bash">$ lsb_release -a
No LSB modules are available.
Distributor ID:    Ubuntu
Description:    Ubuntu 18.04.2 LTS
Release:    18.04
Codename:    bionic</code></pre>
<h1 id="2-apt-get-mysql">2. apt-get mysql</h1>
<ul>
<li>apt를 최신으로 update 하고, mysql-server를 설치한다.</li>
<li>2.1 install mysql <pre><code class="language-bash">$ sudo apt-get update
$ sudo apt-get install mysql-server -y
</code></pre>
</li>
</ul>
<pre><code>
- 2.2 configuring mysql-server
```bash
$ sudo mysql_secure_installation</code></pre><ul>
<li>VALIDATE PASSWORD PLUGIN을 사용할지 : Y(사용)</li>
<li>거의 서비스 목적으로 DB를 사용하기에 password 사용을 활성화 한다<pre><code class="language-bash">Connecting to MySQL using a blank password.
</code></pre>
</li>
</ul>
<p>VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?</p>
<p>Press y|Y for Yes, any other key for No: Y</p>
<pre><code>
- password 유효성 레벨 : 0
- 사용목적에 따라 번호를 입력
```bash
There are three levels of password validation policy:

LOW    Length &gt;= 8
MEDIUM Length &gt;= 8, numeric, mixed case, and special characters
STRONG Length &gt;= 8, numeric, mixed case, special characters and dictionary                  file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 0</code></pre><ul>
<li>새로운 root password 입력<pre><code class="language-bash">Please set the password for root here.
</code></pre>
</li>
</ul>
<p>New password:</p>
<p>Re-enter new password:</p>
<pre><code>
- root password 강도(25)
- root 패스워드 강도를 그대로 사용할지 : Y(사용)
```bash
Estimated strength of the password: 25
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : Y</code></pre><ul>
<li>Anonymous User를 삭제할지 : Y(삭제)</li>
<li>필요에 따라 Y|N 선택<pre><code class="language-bash">Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : Y
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.
</code></pre>
</li>
</ul>
<p>Remove anonymous users? (Press y|Y for Yes, any other key for No) : Y</p>
<pre><code>
- root계정으로 외부에서 접속을 허용할지 : Y(허용)
- 필요에 따라 Y|N 선택
```bash
Normally, root should only be allowed to connect from
&#39;localhost&#39;. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : Y</code></pre><ul>
<li>Test Database를 삭제할지 : Y(삭제)</li>
<li>필요에 따라 Y|N 선택<pre><code class="language-bash">By default, MySQL comes with a database named &#39;test&#39; that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.

</code></pre>
</li>
</ul>
<p>Remove test database and access to it? (Press y|Y for Yes, any other key for No) : Y</p>
<pre><code>
- privileges table을 reload 할지 : Y(허용)
- 필요에 따라 Y|N 선택
```bash
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : Y</code></pre><ul>
<li>필요에 따라 mysql_secure_installation은 다시 설정 가능</li>
</ul>
<h1 id="3-mysql-service-확인">3. mysql service 확인</h1>
<ul>
<li><p>mysql service port(3306)이 열려있는지 확인</p>
<pre><code class="language-bash">$ netstat -ntl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN</code></pre>
</li>
<li><p>만약 mysql service port(3306)가 활성화 되어 있지 않다면, 방화벽에서 그리고 해당 mysql 서비스를 구동시켜야 한다.</p>
<pre><code class="language-bash">$ sudo ufw allow mysql
Rules updated
Rules updated (v6)</code></pre>
</li>
<li><p>local root 접속</p>
<pre><code class="language-bash">$ sudo mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.33-0ubuntu0.18.04.1 (Ubuntu)
</code></pre>
</li>
</ul>
<p>Copyright (c) 2000, 2021, Oracle and/or its affiliates.</p>
<p>Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.</p>
<p>Type &#39;help;&#39; or &#39;\h&#39; for help. Type &#39;\c&#39; to clear the current input statement.</p>
<p>mysql&gt;</p>
<pre><code>

# 4. 외부에서 mysql 접속
- 외부에서 접속하기 위해서는 Mysql의 config 설정 중 bind-address를 ALL IP(0.0.0.0)으로 허용 및 해당 서버에 들어오는 port에 대해 방화벽을 허용해주어야한다.
- AWS EC2를 사용할 경우, 인스턴스의 보안그룹에서 mysql service port(3306)을 인바운드 허용해줘야 한다.
### 4.1 mysql.conf.d 수정
- mysql 5.7 이상에서는 /etc/mysql/mysql.conf.d 디렉토리에  Mysql 기본 config의 프로파일(mysqld.cnf)이 저장되어 있다
```bash
$ sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf</code></pre><ul>
<li><p>bind-address 를 ALL_IP(0.0.0.0)로 변경 또는 추가해준다.</p>
<pre><code class="language-bash">...
#
# Instead of skip-networking the default is now to listen only on
# localhost which is more compatible and is not less secure.
#bind-address           = 127.0.0.1
bind-address            = 0.0.0.0
...</code></pre>
</li>
<li><p>mysql service restart</p>
<pre><code class="language-bash">$ sudo service mysql restart 
$ sudo systemctl restart mysql.service</code></pre>
</li>
</ul>
<h3 id="42-mysql-grant-modify">4.2 MySQL grant modify</h3>
<ul>
<li><p>Mysql은 기본적으로 root 계정을 가지고 있다.</p>
</li>
<li><p>접속하고자 하는 계정을 추가로 만들거나, root 계정을 외부에서 접속할 수 있도록 
Mysql에서 접속 권한을 부여해야한다.</p>
</li>
<li><p>&#39;root&#39;계정으로 어떤 ip든 접속 할 수 있도록 권한 부여</p>
</li>
<li><p>접속하고자 하는 계정의 password 설정</p>
<pre><code class="language-sql">mysql&gt; grant all privileges on *.* to &#39;root&#39;@&#39;%&#39; identified by &#39;루트계정 비밀번호&#39;;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql&gt; FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)</code></pre>
</li>
<li><p>만약 password 길이나 level 관련 에러가 발생할 경우</p>
<pre><code class="language-sql">ERROR 1819 (HY000): Your password does not satisfy the current policy requirements</code></pre>
</li>
<li><p>validate_password_lenth와 validate_password_policy 확인</p>
</li>
<li><p>필요에 따라 길이와 레벨을 수정
```sql
mysql&gt; SHOW VARIABLES LIKE &#39;validate_password%&#39;;</p>
</li>
<li><p>--------------------------------------+--------+
| Variable_name                        | Value  |</p>
</li>
<li><p>--------------------------------------+--------+
| validate_password_check_user_name    | OFF    |
| validate_password_dictionary_file    |        |
| validate_password_length             | 8      |
| validate_password_mixed_case_count   | 1      |
| validate_password_number_count       | 1      |
| validate_password_policy             | MEDIUM |
| validate_password_special_char_count | 1      |</p>
</li>
<li><p>--------------------------------------+--------+
7 rows in set (0.01 sec)</p>
</li>
</ul>
<p>mysql&gt; SET GLOBAL validate_password_policy=LOW;
Query OK, 0 rows affected (0.01 sec)</p>
<p>mysql&gt; SET GLOBAL validate_password_length = 0;
Query OK, 0 rows affected (0.01 sec)</p>
<pre><code>
### 4.3 AWS 보안그룹
- EC2 &gt; 보안그룹 &gt; 해당하는 보안 그룹 이동
- 인바운드 규칙 편집 
- 유형(MYSQL/Aurora), 프로토콜(TCP), 포트범위(3306), 소스(본인선택) 규칙 추가
![](https://images.velog.io/images/inyong_pang/post/4d698813-6521-49e4-8c77-612874ebaf35/image.png)

### 4.4 Mysql 원격 접속 테스트
- MySQL Workbench로 접속 테스트 
- Parameters &gt; Hostname : 서버 호스트(IP) 입력
- Parameters &gt; Username : MySQL 접속 계정
![](https://images.velog.io/images/inyong_pang/post/89e3098c-70ab-42aa-9ea7-c5a742844205/image.png)

- Parameters &gt; Password &gt; Store in Keychain : MySQL 접속 패스워드
![](https://images.velog.io/images/inyong_pang/post/e169579e-0c06-4291-b8f8-95e9929acc15/%5BMySQL%5D%20MySQL5.7%20%E1%84%89%E1%85%A5%E1%86%AF%E1%84%8E%E1%85%B5%20in%20ubuntu_001.png)

- Test Connection 확인
![](https://images.velog.io/images/inyong_pang/post/b07b1bdc-708e-49c5-a827-c1e98be88ebe/%5BMySQL%5D%20MySQL5.7%20%E1%84%89%E1%85%A5%E1%86%AF%E1%84%8E%E1%85%B5%20in%20ubuntu_002.png)

- 실패시, 방화벽(AWS 보안그룹 등) 또는 서버의 방화벽과 MySQL service 확인

---
# Reference

[mysql 설치 in ubuntu](https://dejavuqa.tistory.com/317)

[[EC2] AWS EC2 MySQL 서버를 만들어보자!(외부접속)](https://luji.tistory.com/7)

[[MySQL]패스워드 정책 확인, 변경하기](https://kamang-it.tistory.com/entry/MySQL%ED%8C%A8%EC%8A%A4%EC%9B%8C%EB%93%9C-%EC%A0%95%EC%B1%85-%ED%99%95%EC%9D%B8-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0)
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Devops] 가비아-Route53 DNS 설정 및 SSL 적용]]></title>
            <link>https://velog.io/@inyong_pang/Devops-%EA%B0%80%EB%B9%84%EC%95%84-Route53-DNS-%EC%84%A4%EC%A0%95-%EB%B0%8F-SSL-%EC%A0%81%EC%9A%A9</link>
            <guid>https://velog.io/@inyong_pang/Devops-%EA%B0%80%EB%B9%84%EC%95%84-Route53-DNS-%EC%84%A4%EC%A0%95-%EB%B0%8F-SSL-%EC%A0%81%EC%9A%A9</guid>
            <pubDate>Tue, 23 Feb 2021 02:15:26 GMT</pubDate>
            <description><![CDATA[<h1 id="1-가비아-도메인-확인">1. 가비아 도메인 확인</h1>
<ul>
<li>가비아 로그인 후 My가비아를 통해 도메인통합관리툴 이동</li>
<li>도메인관리 에서 구입한 도메인 선택 후 도메인상세페이지 이동</li>
<li>default로 설정되어 있는 네임서버 확인</li>
</ul>
<h1 id="2-aws-route53-호스팅-영역">2. AWS Route53 호스팅 영역</h1>
<ul>
<li>AWSconsole 에서 Route53 서비스 이동
<img src="https://images.velog.io/images/inyong_pang/post/2f445147-5142-4deb-af61-690a052e7f46/image.png" alt=""></li>
</ul>
<h3 id="21-호스팅-영역-생성">2.1 호스팅 영역 생성</h3>
<ul>
<li>도메인 이름 : 가비아에서 구입한 도메인 입력
<img src="https://images.velog.io/images/inyong_pang/post/d8cabbd9-a9f6-441e-bc45-4f1a2476ad45/image.png" alt=""></li>
<li>Route53 &gt; 호스팅 영역 &gt; 생성한 호스팅 영역 확인</li>
<li>NS 타입의 값/트래픽 라우팅 대상 확인
<img src="https://images.velog.io/images/inyong_pang/post/c747323f-2f4c-46db-9ae0-1950391e874c/image.png" alt=""></li>
</ul>
<h3 id="22-가비아---route53-라우팅-매핑">2.2 가비아 - Route53 라우팅 매핑</h3>
<ul>
<li>가비아 &gt; My가비아 &gt; 도메인통합관리툴 &gt; 도메인관리 &gt; 도메인상세페이지</li>
<li>네임서버를 2.1 호스팅 영역 생성 에서 생성된 NS타입의 값/트래픽 라우팅 대상으로 설정
<img src="https://images.velog.io/images/inyong_pang/post/4c8842a0-598c-4833-92c2-dbf9cc31df19/image.png" alt=""></li>
</ul>
<h1 id="3-aws-certificate-manager">3. AWS Certificate Manager</h1>
<ul>
<li>HTTPS 통신을 하기 위해서는 사설 또는 공인으로부터 받은 SSL/TLS 인증서가 필요.</li>
<li>AWS Certificate Manager(ACM)을 통해 SSL/TLS 인증서를 발급 받는다.</li>
</ul>
<p><img src="https://images.velog.io/images/inyong_pang/post/f97d4429-2e53-4a3a-94d3-8630380a56b0/image.png" alt=""></p>
<ul>
<li>공인 인증서 요청
<img src="https://images.velog.io/images/inyong_pang/post/de764016-b1e2-4e78-8d6f-49479a539639/image.png" alt=""></li>
<li>SSL/TLS 발급 받을 대상 도메인 입력</li>
<li>서브 도메인으로 입력
ex) </li>
<li>*.pang.com 이면, api.pang.com, web.pang.com 등등 어떤 문자열도 받을 수 있는 서브도메인으로 인증서 발급</li>
<li>api.pang.com 이면, api.pang.com 에 대해서만 인증서를 발급
<img src="https://images.velog.io/images/inyong_pang/post/ff3ec4a7-0268-44bb-8025-d79e272e3f6d/image.png" alt=""></li>
<li>검증 방법 선택 : DNS 검증 선택
<img src="https://images.velog.io/images/inyong_pang/post/5174a9b2-5982-4ad1-84c3-21bcc9e7f32c/image.png" alt=""></li>
<li>검증</li>
<li>검증 상태 : 시간이 지나면, 검증 보류 &gt; 검증 완료 로 넘어감</li>
<li>Route53 에서 레코드 생성 클릭
<img src="https://images.velog.io/images/inyong_pang/post/c6d75849-60ca-42fd-8c0b-7b59f36b4511/image.png" alt="">
<img src="https://images.velog.io/images/inyong_pang/post/217166fa-5b4f-4d5e-899f-41582de01dff/image.png" alt=""></li>
<li>Route53 &gt; 호스팅 영역 &gt; 생성한 호스팅 영역 확인</li>
<li>ACM을 통해 인증 요청 및 생성한 레코드 확인, CNAME유형
<img src="https://images.velog.io/images/inyong_pang/post/198be1b1-97f5-49d3-a3d6-414add9ef59f/image.png" alt=""></li>
</ul>
<h1 id="4-로드-밸런싱-설정">4. 로드 밸런싱 설정</h1>
<ul>
<li>도메인에 EC2인스턴스를 라우팅 및 매핑시키기 위해서는 EC2인스턴스로 A유형으로 레코드를 등록해야한다.</li>
<li>HTTP(80)로 통신할 경우, 바로 인스턴스 IP로 레코드등록하면됨.</li>
<li>위 SSL/TLS 인증서를 발급 받고 HTTPS(443)으로 통신할 경우, ELB(Elastic Load Balancer)등록 후, 해당 ELB를 레코드로 등록해야함</li>
</ul>
<h3 id="41-load-balancer-생성">4.1 Load Balancer 생성</h3>
<ul>
<li>EC2 &gt; 로드 밸런싱(Load Balancing) </li>
<li>Load Balancer 생성 클릭</li>
<li>Load Balancer 유형 선택 : Application Load Balancer(HTTP, HTTPS)
<img src="https://images.velog.io/images/inyong_pang/post/e5d9147c-6a7e-4d6f-9351-39d871926b2f/image.png" alt=""></li>
<li>1단계 Load Balancer 구성</li>
<li>기본 구성(이름) : Load Balancer를 해당 도메인에서 구별할 수 있는 이름 입력</li>
<li>리스너 : HTTP(80), HTTPS(443) 추가 및 설정</li>
<li>가용 영역 : 로드 밴런싱 할 네트워크 대역으로 VPC의 가용 영역 체크(2개 이상이여야함)
<img src="https://images.velog.io/images/inyong_pang/post/981a2fee-d7d9-4e48-9a24-6ca5d9b69f80/image.png" alt=""></li>
<li>2단계 보안 설정 구성</li>
<li>인증서 선택 : ACM에서 인증서 선택</li>
<li>인증서 이름 : ACM에서 발급되면 인증서가 drop&amp;down 리스트에 노출됨, 선택
<img src="https://images.velog.io/images/inyong_pang/post/d87e1fab-9515-4c0b-aff7-c10358662872/image.png" alt=""></li>
<li>3단계 보안 그룹 구성</li>
<li>새 보안 그룹 생성 또는 기존에 80, 443 인바운드(허용)되어 있는 정책 선택
<img src="https://images.velog.io/images/inyong_pang/post/1905bca8-ef34-4f9d-8c8b-34696a885d52/image.png" alt=""></li>
<li>4단계 라우팅 구성</li>
<li>대상 그룹(이름) : 구별가능한 대상 그룹명 입력(로드 밸런싱&gt; 대상 그룹에서 확인가능)</li>
<li>포트 : 프로젝트 서비스 포트를 입력(ex. flask project service port : 5000)
<img src="https://images.velog.io/images/inyong_pang/post/9b2732df-eb42-44e6-bdf1-8ac3782d40b5/image.png" alt=""></li>
<li>5단계 대상 등록</li>
<li>인스턴스 리스트에서 프로젝트가 실행되고 있는 인스턴스를 선택</li>
<li>등록된 항목에 추가 선택
<img src="https://images.velog.io/images/inyong_pang/post/d1b7e745-7dac-485f-95f7-838873564122/image.png" alt=""></li>
<li>6단계 검토</li>
<li>검토 후 생성</li>
</ul>
<h1 id="5-호스팅-영역-설정-및-확인">5. 호스팅 영역 설정 및 확인</h1>
<ul>
<li>호스팅 영역 설정에서 ELB 레코드 생성 및 DNS 서비스 확인한다.<h3 id="51-elb-레코드-생성-및-확인">5.1 ELB 레코드 생성 및 확인</h3>
</li>
<li>Route53 &gt; 호스팅 영역 &gt; 생성한 호스팅 영역 이동</li>
<li>레코드 생성 클릭</li>
<li>단순 라우팅 선택
<img src="https://images.velog.io/images/inyong_pang/post/a64b101e-db2b-46b7-8ba2-2326de6555bf/image.png" alt=""></li>
<li>단순 레코드 정의 선택
<img src="https://images.velog.io/images/inyong_pang/post/2eab72da-bae4-4610-a5de-ff3f5dc99b7c/image.png" alt=""></li>
<li>단순 레코드 정의</li>
<li>레코드 이름 : ACM에서 발급 받은 (서브)도메인 입력</li>
<li>레코드 유형 : A-IPv4 주소 및 일부 AWS 리소스로 트래픽 라우팅 선택</li>
<li>갑/트래픽 라우팅 대상 : Application/Classic Load Balance에 대한 별칭 선택</li>
<li>리전 : EC2 인스턴스 리전 선택</li>
<li>로드 밸런서 선택 : 로드밸런싱 에서 생성한 로드밸런서 선택</li>
</ul>
<h3 id="52-dns-서비스-확인">5.2 DNS 서비스 확인</h3>
<ul>
<li>local 환경에서 shell, cmd창을 통해 nslookup 으로 도메인 서비스 확인</li>
<li>DNS 서비스가 될 경우, 해당 도메인에 대한 서비스IP를 확인 가능<pre><code class="language-bash"></code></pre>
</li>
</ul>
<p>~ nslookup api.pang.com
Server:        168.126.63.1
Address:    168.126.63.1#53</p>
<p>Non-authoritative answer:
Name:    api.pang.com
Address: <strong><em>.</em></strong>.<strong><em>.</em></strong>
Name:    api.pang.com
Address: <strong><em>.</em></strong>.<strong><em>.</em></strong></p>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Devops] jenkins-flask 프로젝트 연동]]></title>
            <link>https://velog.io/@inyong_pang/devops-jenkins-flask-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%97%B0%EB%8F%99</link>
            <guid>https://velog.io/@inyong_pang/devops-jenkins-flask-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%97%B0%EB%8F%99</guid>
            <pubDate>Thu, 11 Feb 2021 20:23:59 GMT</pubDate>
            <description><![CDATA[<h1 id="jenkins-plugin-manager">Jenkins Plugin Manager</h1>
<ul>
<li>flask(python) 프로젝트로 python 관련 plugin 필요</li>
<li>Dashboard &gt; Plugin Manager 에서 plugin 검색하여 설치</li>
<li>python, pyenv, post build task, github, bitbucket(옵션) 설치
<img src="https://images.velog.io/images/inyong_pang/post/2e0659a9-ae1e-4ab2-ad46-cb336df8aa71/image.png" alt="">
<img src="https://images.velog.io/images/inyong_pang/post/5b38abf0-58cb-46c5-a3e5-739f9433c977/image.png" alt=""></li>
</ul>
<h1 id="create-ssh-key">create ssh-key</h1>
<ul>
<li>Jenkins과 flask프로젝트(github) 간 소스코드를 주고 받기 위해서는 ssh-key로 서로 ssh 통신을 해야한다</li>
<li>따라서 jenkins 서버에서 ssh-private-key와 ssh-public-key를 생성한다.</li>
</ul>
<ol>
<li>mkdir .ssh</li>
</ol>
<ul>
<li>ssh-key의 권장하는 관리하는 디렉토리는 /var/lib/jenkins/.ssh/</li>
<li>저장 시 추후 관리를 위해 프로젝트 명 별로 관리하는 걸 권장 ex(id_rsa_{프로젝트명})<pre><code class="language-bash">cd /var/lib/jenkins
sudo mkdir .ssh
cd .ssh
pwd
/var/lib/jenkins/.ssh</code></pre>
</li>
</ul>
<ol start="2">
<li>create ssh-key
2-1. ssh-kegen 명령어</li>
</ol>
<ul>
<li>-t 옵션 : 어떠한 암호화 방식을 사용 할 것인지를 지정. ex(rsa)</li>
<li>-b 옵션 : 생성할 키의 bit수를 지정</li>
<li>-C 옵션 : ssh-key의 주석<pre><code class="language-bash">sudo ssh-keygen -t rsa -b 4096 -C &quot;주석쓰&quot;</code></pre>
2-2. ssh 디렉토리 선택<pre><code class="language-bash">Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /var/lib/jenkins/.ssh/id_rsa_{프로젝트명}</code></pre>
2-3. 기타 설정<pre><code class="language-bash">Enter passphrase (empty for no passphrase): {보안암호 설정}</code></pre>
2-4. ssh-keygen Success 화면
```bash
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256: ...
The key&#39;s randomart image is:</li>
<li>---[RSA 4096]----+
...</li>
<li>----[SHA256]-----+
```</li>
</ul>
<p>2.5 ssh-private-key, ssh-public-key 확인</p>
<ul>
<li>ssh-private-key : 서버에서 관리하는 key 공유하면 안됨 ex(id_rsa_{프로젝트명})</li>
<li>ssh-public-key : 클라이언트에서 관리하는 key로 서버에 ssh 접속 시 사용 ex(id_rsa_{프로젝트명}.pub)
```bash
cd /var/lib/jenkins/.ssh
ls -al
total 16
drwxr-xr-x  2 root    root    4096 Feb 11 18:30 .
drwxr-xr-x 15 jenkins jenkins 4096 Feb 11 18:24 ..</li>
<li>rw-------  1 root    root    3243 Feb 11 18:30 id_rsa_{프로젝트명}</li>
<li>rw-r--r--  1 root    root     749 Feb 11 18:30 id_rsa_{프로젝트명}.pub</li>
</ul>
<pre><code>

# setting ssh-public-key in github
- jenkins 서버에서 생성한 ssh-public-key를 해당 flask 프로젝트의 github에 setting 한다
- Github 기준 설정 방법
1. setting &gt; Deploy Keys
![](https://images.velog.io/images/inyong_pang/post/55b7bcf5-d37f-403c-903f-7da2c3feb6c4/image.png)
2. ssh-public-key 입력
- 서버에서 생성된 public-key를 sudo cat 명령어로 확인하여, 값을 복사해서 아래 key Input창에 입력
![](https://images.velog.io/images/inyong_pang/post/56bde3af-d31d-4dcb-bd45-e4a8fd2acc5f/image.png)

# setting ssh-private-key in jenkins
- jenkins 서버에서 생성한 ssh-public-key를 jenkins Credentials 에서 등록한다
- jenkins관리 &gt; Manage Credentials 
![](https://images.velog.io/images/inyong_pang/post/5abfdb34-5ccd-4a4d-a44c-71eda3fe6b66/image.png)

- Kind : SSH Username with private key 선택
- Username : 원하는 유저명
- private Key : (private Key 영역의 id_rsa 값)
![](https://images.velog.io/images/inyong_pang/post/e6c9670f-3e47-411a-9c38-cc45d24d60dd/image.png)

# item create
1. jenkins 메인 화면에서 새로운 item 클릭
- 본인이 원하는 item name 입력 및 &quot;Freestle Project&quot; 선택
![](https://images.velog.io/images/inyong_pang/post/5a3c4a5a-bed8-4542-bd0c-978ff058e709/image.png)

2. 소스 코드 관리
- Repository URL : Github의 SSH 주소 복사 + 붙여놓기
- Credentials : jenkins관리 &gt; Manage Credentials 에서 설정한 키 선택
![](https://images.velog.io/images/inyong_pang/post/a14cbe14-4a6b-4885-9c35-3e626e6ddeba/image.png)

3. 빌드 환경

- pyenv build wrapper : 프로젝트의 python 버전 입력 ex(3.8.5)
![](https://images.velog.io/images/inyong_pang/post/0c130390-912d-4da6-9beb-ee3408af3e0b/image.png)

- 해당 서버에 pyenv 관련 script가 실행되지 않는 경우, 아래와 같은 라이브러리를 설치해야한다
```bash
sudo apt install gcc
sudo apt install make</code></pre><ol start="4">
<li>Build</li>
</ol>
<ul>
<li><p>Jenkins는 소스 코드 관리에서 받은 파일들을 별도 WORKSPACE에서 관리함</p>
</li>
<li><p>따라서 WORKSPACE에서 실제로 실행할 script를 작성하여 빌드를 유발해야함</p>
</li>
<li><p>Execute Shell 을 선택하여 원하는 script를 작성</p>
</li>
<li><p>Python 특성상 pyenv와 pip3를 통해 프로젝트의 필요한 라이브러리를 설치해야함</p>
<pre><code class="language-bash">if [ ! -d &quot;$WORKSPACE/venv&quot; ]; then
python -m venv venv;

if [ -f $WORKSPACE/requirements.txt ]; then
  . $WORKSPACE/venv/bin/activate;
  pip3 install -r requirements.txt;
fi
fi</code></pre>
<p><img src="https://images.velog.io/images/inyong_pang/post/b6218152-97c9-474d-99f6-9c10f141a910/image.png" alt=""></p>
</li>
</ul>
<ol start="5">
<li>빌드 후 조치</li>
</ol>
<ul>
<li>모든 빌드 환경이 완료 된 후 실행하고자 하는 script를 작성</li>
<li>해당 프로젝트는 gunicorn으로 실행하도록 구현<pre><code class="language-bash">PID=`ps -ef | grep commonlife2-admin | awk &#39;{print $2}&#39;`
sudo kill -9 $PID</code></pre>
<pre><code class="language-bash">cd /var/lib/jenkins/workspace/commonlife2-admin
. venv/bin/activate
gunicorn --bind 0:9090 --access-logfile access.log --error-logfile error.log manage:gunicorn_app --daemon --reload</code></pre>
<img src="https://images.velog.io/images/inyong_pang/post/da81db57-bd6e-4be3-8b6a-c58673b8beac/image.png" alt=""></li>
</ul>
<h1 id="수동-빌드-및-확인">수동 빌드 및 확인</h1>
<ul>
<li>Dashbord에서 해당 프로젝트의 설정 확인</li>
<li>Build Now를 통해 수동 빌드 실행 및 결과 확인
<img src="https://images.velog.io/images/inyong_pang/post/02938bcd-5e2b-4ec5-a6b4-96bd868c9760/image.png" alt=""></li>
</ul>
<h1 id="github-webhook">Github WebHook</h1>
<ul>
<li>jenkins이 자동으로 소스코드 확인 및 빌드하기 위해서는 webhook이 필요</li>
<li>github에서 merge 등이 일어나면 jenkins에 webhook message를 던짐</li>
<li>Payload URL : jenkins 아이피와 서비스 포트를 입력
<img src="https://images.velog.io/images/inyong_pang/post/d2536deb-9f5f-481e-961b-3150983de1b7/image.png" alt=""></li>
</ul>
<h1 id="lets-build-test">Let&#39;s Build Test!!</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Devops] Jenkins 설치 및 초기세팅]]></title>
            <link>https://velog.io/@inyong_pang/Jenkins-Jenkins-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%B4%88%EA%B8%B0%EC%84%B8%ED%8C%85</link>
            <guid>https://velog.io/@inyong_pang/Jenkins-Jenkins-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%B4%88%EA%B8%B0%EC%84%B8%ED%8C%85</guid>
            <pubDate>Mon, 08 Feb 2021 09:03:40 GMT</pubDate>
            <description><![CDATA[<h1 id="jenkins-설치">jenkins 설치</h1>
<ol>
<li><p>sudo apt-get update</p>
<pre><code class="language-bash">sudo apt-get update</code></pre>
</li>
<li><p>sudo apt install openjdk-8-jre</p>
<pre><code class="language-bash">sudo apt install openjdk-8-jre -y</code></pre>
</li>
<li><p>check java version</p>
<pre><code class="language-bash">java -version
</code></pre>
</li>
</ol>
<p>openjdk version &quot;1.8.0_275&quot;
OpenJDK Runtime Environment (build 1.8.0_275-8u275-b01-0ubuntu1~18.04-b01)
OpenJDK 64-Bit Server VM (build 25.275-b01, mixed mode)</p>
<pre><code>
4. wget add the jenkins key
```bash
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -</code></pre><ol start="5">
<li><p>add repository</p>
<pre><code class="language-bash">sudo apt-add-repository &quot;deb https://pkg.jenkins.io/debian-stable binary/&quot;</code></pre>
</li>
<li><p>install jenkins</p>
<pre><code class="language-bash">sudo apt install jenkins -y</code></pre>
</li>
</ol>
<p>--</p>
<h1 id="jenkins-service-확인">jenkins service 확인</h1>
<ol>
<li>Jenkins service 확인
1-1. netstat <pre><code class="language-bash">netstat -ntl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp6       0      0 :::22                   :::*                    LISTEN
tcp6       0      0 :::8080                 :::*                    LISTEN</code></pre>
</li>
</ol>
<p>1-2. systemctl status</p>
<pre><code class="language-bash">systemctl status jenkins

● jenkins.service - LSB: Start Jenkins at boot time
   Loaded: loaded (/etc/init.d/jenkins; generated)
   Active: active (exited) since Mon 2021-02-08 03:24:00 UTC; 43s ago
     Docs: man:systemd-sysv-generator(8)
    Tasks: 0 (limit: 1140)
   CGroup: /system.slice/jenkins.service

Feb 08 03:23:59 ip-172-31-47-24 systemd[1]: Starting LSB: Start Jenkins at boot time...
Feb 08 03:23:59 ip-172-31-47-24 jenkins[16659]: Correct java version found
Feb 08 03:23:59 ip-172-31-47-24 jenkins[16659]:  * Starting Jenkins Automation Server jenkins
Feb 08 03:23:59 ip-172-31-47-24 su[16710]: Successful su for jenkins by root
Feb 08 03:23:59 ip-172-31-47-24 su[16710]: + ??? root:jenkins
Feb 08 03:23:59 ip-172-31-47-24 su[16710]: pam_unix(su:session): session opened for user jenkins by (uid=0)
Feb 08 03:23:59 ip-172-31-47-24 su[16710]: pam_unix(su:session): session closed for user jenkins
Feb 08 03:24:00 ip-172-31-47-24 jenkins[16659]:    ...done.
Feb 08 03:24:00 ip-172-31-47-24 systemd[1]: Started LSB: Start Jenkins at boot time.</code></pre>
<hr>
<h1 id="jenkins-service-port-변경">jenkins service port 변경</h1>
<ol>
<li>jenkins default 설정 확인 및 변경</li>
</ol>
<ul>
<li>HTTP_PORT 가 default 8080으로 설정되어 있음</li>
<li>운영환경에 따라 원하는 service port로 변경 </li>
</ul>
<p>1-1. /etc/default/jenkins HTTP_PORT 확인</p>
<pre><code class="language-bash">cat /etc/default/jenkins
...
# port for HTTP connector (default 8080; disable with -1)
HTTP_PORT=8080
...</code></pre>
<p>1-2. /etc/default/jenkins HTTP_PORT 변경</p>
<pre><code class="language-bash">sudo vi /etc/default/jenkins
...
# port for HTTP connector (default 8080; disable with -1)
HTTP_PORT = 9000

...

:wq</code></pre>
<ol start="2">
<li>jenkins service 시작/정지 또는 재시작<pre><code class="language-bash">sudo service jenkins stop
sudo service jenkins start
sudo service jenkins restart</code></pre>
</li>
</ol>
<hr>
<h1 id="jenkins-접속-및-초기-설정">jenkins 접속 및 초기 설정</h1>
<ol>
<li>ec2 security_group 확인 및 변경</li>
</ol>
<ul>
<li>jenkins의 service port를 inbound 정책에서 허용해줘야함
<img src="https://images.velog.io/images/inyong_pang/post/8d95d979-61e3-418a-9fc6-9cc3a4ed98ac/image.png" alt="ec2-security_group(jenkins)"></li>
</ul>
<ol start="2">
<li>jenkins 관리자 페이지 접속</li>
</ol>
<ul>
<li>http:{ip}:{service_port}/ 로 접속</li>
<li>페이지의 디렉토리의 초기 패스워드 확인 및 입력
<img src="https://images.velog.io/images/inyong_pang/post/93051e0e-ba96-4345-99a1-6c8d6cf5a551/image.png" alt=""></li>
</ul>
<ol start="3">
<li>Customize Jenkins</li>
</ol>
<ul>
<li>Install suggested plugins 선택
<img src="https://images.velog.io/images/inyong_pang/post/49b18678-75fd-4996-ad7f-a35c6f7f1f59/image.png" alt=""></li>
</ul>
<ol start="4">
<li>Getting Started</li>
</ol>
<ul>
<li>기본 플러그인 설치</li>
<li>차 한잔 하고 오면 됨
<img src="https://images.velog.io/images/inyong_pang/post/a313538b-296f-4c62-81c8-03d7297b2e3c/image.png" alt=""></li>
</ul>
<ol start="5">
<li>Create First Admin User</li>
</ol>
<ul>
<li>초기 어드민 계정 생성</li>
<li>패스워드 까먹으면...안됨
<img src="https://images.velog.io/images/inyong_pang/post/782432d5-21b6-4a3b-b2c3-3509ffcf6ef3/image.png" alt=""></li>
</ul>
<ol start="6">
<li>젠킨슨은 준비됬어!
<img src="https://images.velog.io/images/inyong_pang/post/bdac63bd-fb76-48e9-bcc0-482fb92864a3/image.png" alt=""></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] 중복 레코드 처리 방법]]></title>
            <link>https://velog.io/@inyong_pang/MySQL-%EC%A4%91%EB%B3%B5-%EB%A0%88%EC%BD%94%EB%93%9C-%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@inyong_pang/MySQL-%EC%A4%91%EB%B3%B5-%EB%A0%88%EC%BD%94%EB%93%9C-%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Mon, 04 Jan 2021 05:04:14 GMT</pubDate>
            <description><![CDATA[<h1 id="중복-레코드">중복 레코드</h1>
<blockquote>
<p>MySQL에서 테이블에 레코드를 INSERT할 때, PK가 DUPLICATE 되는 현상이 번번히 일어난다.</p>
</blockquote>
<ul>
<li>ex) 공간가격-날짜 복합키를 해당 테이블에 INSERT할 때, 중복일 경우<pre><code class="language-sql">ERROR 1062 (23000): Duplicate entry &#39;SPAC00000001-2020-12-07&#39; for key &#39;tb_guesthouse_price_calendar.PRIMARY&#39;</code></pre>
따라서 위 와 같은 현상을 해결하고자 한다면, 
해당 데이터를 INSERT하지 않거나, 해당 레코드를 UPDATE를 해야한다.
MySQL에서는 다음 3가지 방법으로 해결할 수 있다.</li>
</ul>
<hr>
<h1 id="insert-ignore">INSERT IGNORE</h1>
<p>말 그대로 삽입(INSERT)하되, duplicate가 발생한다면, 해당 레코드는 무시하고 넘어가는 방법이다.
즉, ERROR를 무시하고 INSERT만 하는 명령어이다.</p>
<pre><code class="language-sql">INSERT IGNORE INTO `USER`
(
    email
    , name
) VALUES 
(&#39;test01@gmail.com&#39;, &#39;test01&#39;)
;

Query OK, 0 rows affected (0.00 sec)</code></pre>
<ul>
<li>기존에 &#39;test01@gmail.com&#39; 이라는 레코드가 있기 때문에, Query는 실행됬으나, 반영된 레코드의 수는 0 이다.</li>
</ul>
<hr>
<h1 id="replcate-into">REPLCATE INTO</h1>
<p>말 그대로 삽입(INSERT)하되, duplicate가 발생한다면, 기존의 레코드는 삭제가 되고, 새로운 PK로 Auto Increment가 되어 새로운 레코드로 삽입한다.</p>
<pre><code class="language-sql">REPLCATE INTO `USER`
(
    email
    , name
) VALUES
(&#39;test01@gmail.com&#39;, &#39;test01&#39;)
;

Query OK, 2 rows affected (0.00 sec)</code></pre>
<ul>
<li>기존에 해당하는 레코드가 있기 때문에, 기존것은 삭제되고 새로 INSERT 한다.</li>
<li>따라서 Query는 실행되고, 2개의 레코드에 반영되었다.</li>
</ul>
<hr>
<h1 id="on-duplicate-key-update">ON DUPLICATE KEY UPDATE</h1>
<p>역시 말 그대로 duplicate가 발생할 때, 해당 KEY에 대해서 수정(UPDATE)하는 명령어이다.
기존 레코드의 PK는 그대로 두고 UPDATE를 하기 때문에, REPLCATE INTO 처럼 PK가 새로 생성 될 필요 없다.</p>
<pre><code class="language-sql">INSERT INTO `USER`
(
    email
    , name
    , phone_number
) VALUES 
(&#39;test01@gmail.com&#39;, &#39;test01&#39;, &#39;01011112222&#39;)
ON DUPLICATE KEY UPDATE
name = &#39;test01&#39;
, phone_number = &#39;01011112222&#39;
;

Query OK, 2 rows affected, 1 warning (0.00 sec)</code></pre>
<ul>
<li>기존에 해당 데이터가 있기 때문에, Query는 실행됬고, 2개의 레코드에 반영되었으며, 1개의 warning이 발생한다.</li>
<li>warning은 수정되었기 때문에 발생한다.</li>
</ul>
<blockquote>
<p>MySQL 중복 레코드 처리방법 참고</p>
</blockquote>
<ul>
<li><a href="http://jason-heo.github.io/mysql/2014/03/05/manage-dup-key2.html">MySQL 중복 레코드 관리 방법 - Jason Heo&#39;s Blog</a></li>
<li><a href="https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html">MySQL INSERT ... ON DUPLICATE KEY UPDATE Statement</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] MySQL Variables(변수) 만들기]]></title>
            <link>https://velog.io/@inyong_pang/MySQL-MySQL-variables%EB%B3%80%EC%88%98-%EB%A7%8C%EB%93%A4%EC%96%B4%EC%84%9C-%EC%9D%91%EC%9A%A9%ED%95%98%EA%B8%B0getidPK</link>
            <guid>https://velog.io/@inyong_pang/MySQL-MySQL-variables%EB%B3%80%EC%88%98-%EB%A7%8C%EB%93%A4%EC%96%B4%EC%84%9C-%EC%9D%91%EC%9A%A9%ED%95%98%EA%B8%B0getidPK</guid>
            <pubDate>Mon, 04 Jan 2021 02:45:25 GMT</pubDate>
            <description><![CDATA[<h1 id="what-the-mysql-variable">What the MySQL variable!?</h1>
<blockquote>
<p>흔히 다들 알다시피, variable(변수)란 값을 담아두는 것
SQL에서도 variable(변수)화 시켜서 특정값을 담아두고 사용이 가능
변수를 담는 방법은 크게 3가지
사용자 정의 변수, 지역 변수, 시스템 변수 </p>
</blockquote>
<hr>
<h1 id="사용자-정의-변수">사용자 정의 변수</h1>
<p>사용자가 직접 정의하는 변수로써, 정수, 10진수, 부동 소수점, 2진수 또는 이진문자열 또는 NULL 값과 같은 제한된 데이터 유형 세트에서 값을 지정할 수 있다.
그리고 변수는 세션(Session)단위로 실행이 되기 때문에, 한 클라이언트에서 정의한 사용자 변수는 다른 클라이언트에서 보거나 사용할 수 없다.</p>
<h3 id="사용자-정의-변수-선언_1">사용자 정의 변수 선언_1</h3>
<pre><code class="language-sql">SELECT @var;</code></pre>
<p><img src="https://images.velog.io/images/inyong_pang/post/ab22e343-505b-479b-a418-711f9fd531b5/image.png" alt=""></p>
<ul>
<li>초기화 하지 않은 변수를 선언 시, 기본 NULL 값을 갖는다.</li>
</ul>
<h3 id="사용자-정의-변수-선언_2">사용자 정의 변수 선언_2</h3>
<pre><code class="language-sql">SET @start = 1, @finish = 10;

SELECT @start := 1, @finish := 10;</code></pre>
<p><img src="https://images.velog.io/images/inyong_pang/post/3fa91c2c-1e25-4ce7-b2c1-6840944d0cfb/image.png" alt=""></p>
<ul>
<li><code>SET @변수명</code> 을 사용시 <code>=</code> 대입연산자를 사용한다</li>
<li><code>SELECT @변수명</code> 을 사용시 <code>:=</code> 과 같은 대입연산자를 사용한다.</li>
</ul>
<h3 id="사용자-정의-변수-조회-및-활용">사용자 정의 변수 조회 및 활용</h3>
<pre><code class="language-sql">SELECT * FROM tb_code WHERE code_cd BETWEEN @start AND @finish;</code></pre>
<p><img src="https://images.velog.io/images/inyong_pang/post/27cefaba-a752-42df-93bd-d4206f847fbb/image.png" alt=""></p>
<ul>
<li><code>tb_code</code> 테이블에서 <code>code_cd</code> 가 1 부터 10까지 해당하는 데이터를 조회</li>
</ul>
<blockquote>
<p>사용자 정의 변수 참고 </p>
</blockquote>
<ul>
<li><a href="https://dev.mysql.com/doc/refman/8.0/en/user-variables.html">https://dev.mysql.com/doc/refman/8.0/en/user-variables.html</a></li>
</ul>
<hr>
<h1 id="지역-변수">지역 변수</h1>
<p>지역(로컬)변수는 프로시저(Procedure) 또는 트리거(Trigger) 내에서 로컬 변수 및 입력 매개 변수로 사용할 수 있다.
즉, Declares 내 지역(로컬)변수를 사용함을 의미 한다.</p>
<h3 id="지역-변수-활용">지역 변수 활용</h3>
<ul>
<li><p>8자리 PK 코드를 생성하는 sequence 함수</p>
<pre><code class="language-sql">DELIMITER ;;
CREATE FUNCTION MySQL.`fn_get_seq_8`(`p_seq_name` VARCHAR(4)) 
RETURNS varchar(8) CHARSET utf8
BEGIN
  DECLARE RTN_VAL VARCHAR(8);

  INSERT INTO MySQL.tb_sequence (seq_name, seq_no)
       values (p_seq_name, LAST_INSERT_ID(1))
  ON DUPLICATE KEY UPDATE seq_no=LAST_INSERT_ID(seq_no+1);

  set @ret = row_count();

  if @ret = 0 then 
      set RTN_VAL = &#39;0&#39;; 
  else
      SET RTN_VAL = (SELECT CONCAT(p_seq_name,  LPAD(LAST_INSERT_ID(),4,&#39;0&#39;))); 
  end if;

  RETURN RTN_VAL;
END ;;
DELIMITER ;</code></pre>
</li>
<li><p>지역변수 예시 <a href="https://velog.io/@inyong_pang/MySQL-MySQL-Sequence-%EB%A7%8C%EB%93%A4%EA%B8%B0">MySQL Sequence 만들기</a></p>
</li>
</ul>
<blockquote>
<p>지역 변수 참고:</p>
</blockquote>
<ul>
<li><a href="https://dev.mysql.com/doc/refman/8.0/en/declare-local-variable.html">https://dev.mysql.com/doc/refman/8.0/en/declare-local-variable.html</a></li>
</ul>
<hr>
<h1 id="시스템-변수">시스템 변수</h1>
<p>MySQL은 기본적으로 선언된 변수들이 존재한다. 이를 시스템 변수라 한다.
시스템 변수는 GLOBAL 또는 세션단위로 사용가능하다.
즉, 서버의 전체 작업과 클라이언트 연결 후 작업등 모든 부분에 영향을 준다.</p>
<h3 id="시스템-변수-선언">시스템 변수 선언</h3>
<pre><code class="language-sql">-- Syntax to Set value to a Global variable:
SET GLOBAL sort_buffer_size=1000000;
SET @@global.sort_buffer_size=1000000;

-- Syntax to Set value to a Session variable:
SET sort_buffer_size=1000000;
SET SESSION sort_buffer_size=1000000;
SET @@sort_buffer_size=1000000;
SET @@local.sort_buffer_size=10000;</code></pre>
<h3 id="시스템-변수-확인">시스템 변수 확인</h3>
<pre><code class="language-sql">-- 모든 변수 확인
SHOW VARIABLES;

-- 특정 변수 확인
SELECT @@sort_buffer_size;</code></pre>
<blockquote>
<p>시스템 변수 참고:</p>
</blockquote>
<ul>
<li><a href="https://dev.mysql.com/doc/refman/8.0/en/using-system-variables.html">https://dev.mysql.com/doc/refman/8.0/en/using-system-variables.html</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>