Virtualenv로 Python2, Python3 환경 만들기

Python을 쓸 때 virtualenv는 필수였다. 거기에 덤으로 virtualenvwrapper도 같이 쓰곤 했다.

그러던 중 누군가 나에게 말했다.

아직도 Python2를 쓴다고? 이제 대세는 Python3이야!

팔랑귀였던 나는 당장 Python3을 설치했다.

하지만 뭔가 문제가 생겼다.
터미널에서 virtualenv + virtualenvwrapper의 조합으로 가상환경을 구성해 쓰던 나였는데 virtualenv 이 놈은 Python2만 바라보고 있으니 Python3는 가상환경을 구성하지 못하는 불편함이 있었다.

혹시 방법이 있을까해서 help를 쳐봤다.

1
2
3
4
5
6
7
8
9
10
11
$ mkvirtualenv --help
...

-p PYTHON_EXE, --python=PYTHON_EXE
The Python interpreter to use, e.g.,
--python=python2.5 will use the python2.5 interpreter
to create the new environment. The default is the
interpreter that virtualenv was installed with
(/usr/local/opt/python/bin/python2.7)

...

나같은 사람이 나뿐만이 아니었나보다.

방법

1
2
3
4
5
6
$ mkvirtualenv -p /usr/local/bin/python3 python3

...

(python3) $ python --version
Python 3.5.2

mkvirtualenv -p <PYTHON_PATH> <VIRTUALENV_NAME>

이 명령어를 기억하자.

그리고

conda라는 것도 있던데 나중에 한번 써봐야겠다.

Jupyter에 virtualenv 커널 추가하기

보통 Python 을 쓸 때 virtualenv 를 사용해 독립적인 환경을 구성해놓고 썻다.

virtualenv 를 사용하면 각 환경 별로 패키지를 달리 설치하여 충돌도 막아주고 깔끔한 개발 환경은 지원해주기 때문이다.

하지만 Jupyter 는 개발 환경에 독립적일 필요가 없으니 virtualenv 에 가두지 않고 글로벌하게 설치했다.

그리고 당연하게도 Jupyter 에서 virtualenv 에 설치된 패키지들에 접근하지 못했다.

순간 “그럼 virtualenv 안에 Jupyter 를 설치해야 되는구나!” 라는 생각을 했지만 이건 아닌것 같아서 구글링을 시작했다.

그리고 역시 은 있었다!

설정

일단 적당한 virtualenv를 만들어 놓자.

Jupyter 의 설정들을 보기 위해 터미널에서 jupyter --paths 를 입력한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
$ jupyter --paths
config:
/Users/mac/.jupyter
/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/etc/jupyter
/usr/local/etc/jupyter
/etc/jupyter
data:
/Users/mac/Library/Jupyter
/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/share/jupyter
/usr/local/share/jupyter
/usr/share/jupyter
runtime:
/Users/mac/Library/Jupyter/runtime

그리고 아까 생성한 virtualenv 를 활성화하고, which python 명령어로 가상환경의 위치를 파악한다.

1
2
(tensorflow) $ which python
/Users/mac/.envs/tensorflow/bin/python

그리고 ipykernel 모듈을 설치한다.

1
(tensorflow) $ pip install ipykernel

이제 Jupyter 에 kernel을 추가만 하면 된다.(까먹지말자)

1
$ mkdir /Users/mac/Library/Jupyter/kernels/tensorflow

마지막으로 kernel.json file을 하나 생성해주자.

1
2
3
4
5
6
{
"argv": [ "/Users/mac/.envs/tensorflow/bin/python", "-m", "ipykernel",
"-f", "{connection_file}"],
"display_name": "tensorflow",
"language": "python"
}

그리고 Jupyter를 실행하고 확인하면!

jupyter_1

tensorflow 라는 커널이 추가된 것을 확인할 수 있다!

Refer

블로그에 SEO 적용하기

블로그를 팠는데 나만 볼수 있는 블로그가 되었다.
인터넷에서 검색을 해도 내 블로그는 나오지 않아…

뭐가 문제일까 고민하다가 답을 찾았다.

SEO

SEO(Search Engine Optimization)는 말 그대로 검색엔진 최적화를 하는 것이다.
사이트를 구글, 네이버, 다음과 같은 검색엔진에 검색이 되게 만드는 과정을 말한다.

Jekyll 블로그를 설치하면 기초적인 meta태그들은 생성되어 있기 때문에 기본적인 SEO는 되어 있다.

1
2
<title>{% if page.title %}{{ page.title | escape }}{% else %}{{ site.title | escape }}{% endif %}</title>
<meta name="description" content="{% if page.excerpt %}{{ page.excerpt | strip_html | strip_newlines | truncate: 160 }}{% else %}{{ site.description }}{% endif %}">

title과 description 태그는 꼭 추가하자!

그래서 그 이상으로 뭘 해야 더 검색엔진에서 잘 나올까? 를 알아보자.

meta 태그

엥 아까 meta 태그들을 기본적으로 생성해준다고 하지 않았나? 라고 하시는 분들이 있을텐데

기본적으로 생성해주는 태그들 이외에 좀 더 추가하면 좋은 태그들이 있다.

그것은 바로 og 태그!

og 태그는 Open Graph Protocol에 정보를 제공해주는 태그인데, 카카오톡이나 페이스북에서 url을 공유하면 생성되는 이미지나 텍스트들이 이 태그에서 비롯되어 보이는 것이다.

이 태그에 올바른 정보가 들어 있는 사이트인 경우 검색엔진의 우선순위가 올라간다.

1
2
3
4
5
6
7
8
<meta property="og:title" content="{% if page.title %}{{ page.title | escape }}{% else %}{{ site.title | escape }}{% endif %}">
<meta property="og:description" content="{% if page.excerpt %}{{ page.excerpt | strip_html | strip_newlines | truncate: 160 }}{% else %}{{ site.description }}{% endif %}">
<meta property="og:type" content="website">
<meta property="og:url" content="{{ page.url | replace:'index.html','' | prepend: site.baseurl | prepend: site.url }}"/>
<meta property="og:image" content="{{ site.url }}/images/songyunseop.jpeg"/>
<meta property="og:image:width" content="420" />
<meta property="og:image:height" content="420" />
<meta property="og:image:type" content="image/png">

위 처럼 각 태그에 content 값을 적당히 넣어 주면 된다.

sitemap.xml & robots.txt

일단 sitemap.xml은 검색 엔진에서 크롤링을 할 페이지들을 결정해주는 xml 파일인데, Jekyll에서는 간단하게 루비 젬을 추가하면 생성할 수 있다.(Jekyll 짱)

1
2
gems:
- jekyll-sitemap

config.yml 파일에 저렇게 추가하면 된다.
자세한건 여기에서 확인하자.

그러면 사이트 상위에 파일이 생긴걸 확인할 수 있다.(https://songyunseop.github.io/sitemap.xml)

robots.txt는 검색 엔진의 크롤러들이 웹 사이트에서 어떤 페이지를 크롤링하고, 어떤 페이지를 제외할지 정보를 주는 파일이다.

1
2
User-agent: *
Sitemap: https://songyunseop.github.io/sitemap.xml

이렇게 작성하고 robots.txt 라는 이름으로 사이트 맨 상위에 넣어두면 된다.(https://songyunseop.github.io/robots.txt)

https

문서를 보면 https를 사이트에서 지원하는지 안하는지에 따라 검색엔진의 우선순위가 갈린다고 한다.

이 블로그는 Github에서 제공하는 인증서로 https를 지원하는데 혹시나 개인 호스팅을 해서 ssl 인증서를 발급 받으려면 Let’s encrypt를 한번 사용해보자.

설치과정과 적용 방법은 이 블로그의 다른글에서 확인할 수 있다.

Google Webmaster

https://www.google.com/webmasters/

몇가지 간단한 단계를 거치면 Google Webmaster에 내 블로그를 추가 할 수 있는데 사실 위의 과정들을 다 체크를 해줄 뿐만 아니라, 다른 유용한 정보도 확인할 수 있다.

또 여기서 매우 중요한 기능중 하나가 Fetch As Google이라는 건데 내 페이지를 크롤링 해보고 이상이 없으면 구글에서 색인해달라고 요청까지 해준다.

Fetch As Google

위 사진에서 보이는 것 처럼 두가지 옵션이 있는데, 이 URL만 크롤링하거나, 이 URL 및 직접 연결되는 링크도 크롤링을 할 수 있다.

색인 요청을 하면 구글에 그 페이지를 검색했을 때 예전보다는 빨리 발견할 수 있을 것이다.

그 외에도 Google Analytics에 붙이면 더 많은 정보들을 확인할 수 있다.

추가로 Naver Webmaster도 있는데 기능은 비슷하므로 생략한다.

Social Share

지금의 구글을 만드는데 기반이 되었던 PageRank 알고리즘에 의하면 ‘많은 페이지에서 참조하는 페이지일수록 신뢰성 있고 영향력 있을 수 있다’고 한다.

여기서 참조 되었다는 것은 이 페이지의 링크를 다른 웹 페이지 문서가 포함하고 있다는 뜻이다.

그러므로 사이트의 링크가 다른 여러 사이트에서 참조되어 있다면 그 사이트의 순위는 당연히 올라갈 것이다.

자 그러면 바로 아래의 공유 버튼을 한번씩 눌러보자.

JavaScript에서 string을 replaceAll 하고싶을 때

javascript에서 스트링을 replace할때 당황스러웠던 적이 있었다.

1
2
> "javascript".replace("a","b")
'jbvascript'

저렇게 앞의 한글자만 replace를 해주기때문이다.
어떻게하면 깔끔하게 할 수 있을지 구글링하다보니 역시 답이 나왔다.

정규식을 이용해서 replace를 하면되는데

1
2
> "javascrip".replace(/a/gi,"b")
'jbvbscript'

저 뒤에 있는 gi는 정규표현식 옵션이다.

  • g : global
  • i : ignore case
  • m : multiline

좀 찾아보니 정규표현식을 쓰지않고 다른방법으로 쓰는 경우도 있었다.

1
2
3
4
5
6
function replaceAll(str, searchStr, replaceStr) {
return str.split(searchStr).join(replaceStr);
}

> replaceAll("javascript", "a", "b")
'jbvbscript'

이렇게 또 하나 알아갑니다.

Refer

라즈베리파이와 페이스북 메신저를 사용한 온습도 모니터링 봇 개발

집이 1층인데 햇빛도 잘 안들어오고 환기도 잘 안되서 거의 항상 습하고 곰팡이도…
어느 주말에 그날도 역시 습한 집에 누워있다가 갑자기 집이 도대체 얼마나 습한건지 궁금해졌다.
어떻게 할까 고민하던 중 작년에 IoT관련 세미나에서 받은 라즈베리파이와 키트를 살펴보니 온습도 센서를 발견했다.(이거다!)
그래서 무작정 개발해보기로 했다.

개발 구상

  • 라즈베리파이와 온습도 센서를 통해 데이터 가져오기
  • 온습도 데이터를 저장하고 웹에서 간단히 보여줄 수 있는 웹 서버 개발
  • (후에 추가된) 온습도 모니터링해서 알려주는 봇 개발

이렇게만 하면 되겠지..?

라즈베리파이

일단 라즈베리파이에 Thing+가 셋팅되어 있었는데, 그 API를 활용해서 데이터를 불러오려고 시도했다. 하지만 뭔가 잘못된것인지 라즈베리파이와 연동이 안되서 실패했다.
그래서 그냥 빵판에 연결해서 데이터를 뽑아보는 방법으로 바꿨는데 하다보니 좋은 오픈소스도 있어서 쉽게 할 수 있었다.

회로도

[출처] Adafruit

위 그림처럼 회로를 연결하고 테스트를 해봤다. 필요한 소스는 Adafruit_Python_DHT 여기에서 구할 수 있었다.

1
2
$ python AdafruitDHT.py 11 4
Temp=31.0* Humidity=42.0%

그리고 저 라이브러리를 사용해서 얻은 온습도 데이터를 10초마다 보낼 수 있게 crontab을 사용했다.

1
2
3
4
5
6
7
8
9
10
11
12
import Adafruit_DHT
import requests
import datetime

humidity, temperature = Adafruit_DHT.read_retry(11, 4)

data = {'humidity': humidity, 'temperature': temperature, 'ticktime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

url = 'SERVER_URL'

res = requests.post(url, data=data)
res.content

웹 개발

라즈베리파이로 자체 웹서버를 올려서 사용할까도 생각했었는데 공유기로 연결을 해둬서 그런가 IP포워딩등 여러가지 설정할것이 있어서 그냥 Microsoft의 Azure를 사용하기로 했다.
기본적으로 Node.js + Express 로 웹서버를 구축하고 라즈베리파이에서 전송한 데이터를 몽고디비에 저장하는 API하나를 만들고, 웹 페이지에서 마지막 업데이트 시간과 온도, 습도를 보여주는 페이지를 개발했다.
시간대별로 온습도가 어떻게 변하는지 보고싶어서 plotly.js 라이브러리를 사용해서 그래프를 쉽게 만들었다.
다만 모바일 화면에서 너무 찌그러져보이는 단점이 있는데 커스터마이징을 할 수 있는 d3.js로 나중에 바꿀 생각이다.

생각보다 빠르고 쉽게 구축을 했는데, 막상 웹 페이지에서 보는것만 있으니 조금 별로였다. 쾌적한 온습도 범위를 벗어나면 내가 알 수 있는 어떤 장치가 필요하다고 생각했다.

OMSH WEB

메신저 개발

사실 처음에는 (이미 해봤던)슬랙 API를 활용해서 만들려고했다.
하지만 좀 새로운 것이 없을까 하다가 슬랙과 유사한 서비스인 잔디에도 비슷한 기능이 있을 것 같아서 찾아보니 역시 있었다.
그래서 내가 원하는 습도가 넘어가면 알림을 Jandi Webhook 을 통해 알림을 줄 수 있게 해놨다.

Jandi Webhook Noti

오예!

그런데 이렇게 막상 만들고나니 습도가 높아졌을 때 알림이 오는건 좋은데 내가 원할 때마다 웹 페이지에 접속하고 보는게 생각보다 불편했다.
그래서 뭔가 대안이 없을까 생각을 하다가 요즘 핫하다는 Facebook Messenger 로 온습도를 알려주는 Bot을 만들기로 했다.

막상 한다곤 했지만 아는게 없어서 일단 이 링크를 따라했다.
생각보다 훨씬 빠르고 간단하게 개발이 완료되었는데, 여기에 뭐 쓰기도 애매한 수준이라 생략하겠다.(저 링크에 더 자세히 나온다.)

OMSH Bot

Refer

Let's Encrypt 인증서 설치하기(feat. Ubuntu 14.04, Nginx)

웹이 어느정도 개발되고 이제 고도화를 해야할 단계가 왔다.
그 중에 보안을 위해 Https를 도입하는 것이 우선시 되었는데, Https를 사용하기 위해서는 ssl 인증서가 필요했다.
ssl 인증서를 구입해서 쓰는 것 보다 언젠가 들어본 Let’s Encrypt를 쓰기로 했다.

Let’s Encrypt

Let's Encrypt

쉽게 말하자면 인증서를 무료로 제공하는 인증기관이다.
mozilla, cisco, facebook 등 후원하는 곳들도 많은 것을 보니 믿을만 할 것 같다.

사용 방법

저번에는 letsencrypt repository를 클론 받아서 사용했었는데, 이제 client가 나온 것 같았다.
홈페이지에서도 certbot이라는 클라이언트를 사용하는 것을 추천했다.
들어가보니 첫 페이지에서 Webserver와 OS를 선택하면 그에 맞는 설치 방법도 친절하게 알려줬다.

0. 환경

요즘 개인적으로 하고있는 프로젝트가 있는데 Https를 도입할 일이 있어서 그 서버에서 진행하기로 했다.
Azure, Ubuntu 14.04, Nginx
이런 조합이다.

1. Install

1
2
3
4
$ wget https://dl.eff.org/certbot-auto
$ chmod a+x certbot-auto

$ ./certbot-auto

2. 인증서 발급

1
$ ./certbot-auto certonly

어떤 방식으로 인증을 할거냐 물어보는데 Webserver(nginx)를 따로 사용하고 있으므로 1번을 선택한다.

letsencrypt_1

도메인 이름을 적으면됨

letsencrypt_2

webroot를 /var/www/ 로 설정하고

letsencrypt_3
letsencrypt_4

nginx conf 파일에 이렇게 추가해두었다.

1
2
3
location /.well-known {
root /var/www;
}

아래와 같은 메시지가 출력되면 성공한건데, /etc/letsencrypt 위치에 설치되어있다.

1
2
3
4
5
6
7
8
9
10
11
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/{domain}/fullchain.pem. Your cert will expire
on 2016-11-10. To obtain a new or tweaked version of this
certificate in the future, simply run certbot-auto again. To
non-interactively renew *all* of your certificates, run
"certbot-auto renew"
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

3. ssl 적용

nginx에 ssl config 파일을 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
server{
listen 443 ssl;
server_name {server name};

ssl_certificate /etc/letsencrypt/live/{domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{domain}/privkey.pem;


ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;

location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:3000;
}

}

dhparam 파일은 아래와 같은 코드로 생성했다.

1
openssl dhparam -out dhparam.pem 2048

4. 확인

nginx를 reload하고 브라우저에서 https로 접속한다.

1
$ service nginx reload

적용 된걸 확인할 수 있다.

letsencrypt_5

5. renew

Let’s encrypt의 (내가 생각하는)유일한 단점이 기간이 너무 짧다는 것이다.
발급이 성공하면 만료 날짜가 나오는데 3개월 후인가 그럴것이다.
다음 명령어로 리뉴얼을 할 수 있다.

1
$ ./certbot-auto renew

하지만 이것도 스크립트를 짜면 자동화 할 수 있다.
그건 리뉴얼할 시기가 다가오면 따로 정리하는 것으로 하자.(절대 귀찮아서가 아니다.)

그 외

찾아보니 무료로 인증서를 발급해주는 기관들이 조금 더 있었다.

Refer

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×