2017年5月9日 星期二

Docker 學習筆記 - Part 2

事前準備:

  • 安裝 Docker 1.13 以上版本
  • 讀過 Part 1
  • 確定你的環境,並執行 docker run hello-world

介紹:

我們可以開始用docker 的方式來建立我們的程式。 首先我們要建立container, 好讓我們的程式在上面跑。再container 上面的app, service , service, stack , 以後的章節再介紹。

  • Stack
  • Services
  • Container (我們目前在此階段)

我的新開發環境:

以往我們要開放一支新的程式,如 Python 程式,首先必需在電腦上安裝 Python 開發環境。但這會造成你在你的主機裡建立一個你在開發 python 程式時所需的環境,但程式移到server 時,就可以跑你寫出的程式嗎?

透過 Docker,你可以只安裝 python 執行環境 包成一個 image,而不需再重新安裝一次python 環境。而且,你的image 也可以包含你開發的app,確定你的程式,和其相依套件,都可以一起包進image 內。 這種 可攜式的image, 就稱作 Dockerfile

Dockerfile 來定義一個 container

Dockerfile 用來定義你想要你的container 內是什麼樣的環境,取在這image 環境內的虛擬化的主機資源(如網路介面和磁碟檔案),因為已經被隔離在主機外了,所以你必需自己去對映 port 到外面的世界(有點像網路的 pat 或 nat)。並指定你想要把檔案 copy 進你的container 環境裡。做完後,你就可以期待你的程式在 Dockerfile內設定好而建立的docker 內,順利執行了,拿去那裡,都可以順利執竹。

Dockerfile

先建立一個空的目錄,然後把以下內容建立成一個檔案名稱Dockerfile 的檔案。#代表註解。

# Use an official Python runtime as a base image
FROM python:2.7-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
ADD . /app

# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt

# Make port 80 available to the world outside this container
EXPOSE 80

# Define environment variable
ENV NAME World

# Run app.py when the container launches
CMD ["python", "app.py"]

這個 Dockerfile 裡面有兩個我們還沒建立的東西,即 app.py 和 requirements.txt


app 本身

上述兩個檔案也要放在和Dockerfile同一個目錄內。這樣就可以完成我們app 的環境,簡單吧。 當上述的 Dockerfile 被建立到 image 內後,app.py 和 requirements.txt 都會被包含在內,因為Dockerfile 使用 ADD 指令。而從 app.py的輸入則可以透過HTTP來讀取,因為我們在 Dockerfile內用了EXPOSE
from flask import Flask
from redis import Redis, RedisError
import os
import socket

# Connect to Redis
redis = Redis(host="redis", db=0)

app = Flask(__name__)

@app.route("/")
def hello():
    try:
        visits = redis.incr('counter')
    except RedisError:
        visits = "<i>cannot connect to Redis, counter disabled</i>"

    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>" \
           "<b>Visits:</b> {visits}"
    return html.format(name=os.getenv('NAME', "world"), hostname=socket.gethostname(), visits=visits)

if __name__ == "__main__":
 app.run(host='0.0.0.0', port=80)

然後我們可以看到 在 Dockerfile 內有一行 pip install requirements.txt 安裝了 Flask 和 Radis 的Python 函式庫。而我們的app 程式列出環境變數 NAME, 當它執行到 docker.gethostname()會用到。最後,因為 Redis 無法執行(我們只是將它的 python 函式include進來,而非 Redis 程式),所以我們會得到一個錯誤訊息,而無法再繼續程式。


來建立 app 吧

好了!你不需要在你的主體主機裡安裝python 或 requirements.txt裡的東西,也不需要建立或安裝這個image 在你的主體主機裡。看來雖然好像你還沒建立好 Python 和 Flask 的環境,但實事上你已經建好了。
我們ls 一下看看:

$ ls
Dockerfile              app.py                  requirements.txt

OK, 我們要開始建立我們的image 了。我們會用參數 -t 來建立一個 image 的名字。

docker build -t friendlyhello .
那建立出來的image 放在那呢?它會被docker 放在 你主體主機的 Docker image registry 指定的位置裡。用下列指令就可以知道 你的image 有那些:


$ docker images

REPOSITORY            TAG                 IMAGE ID
friendlyhello         latest              326387cea398


執行app

要執行我們的 app.py 要先把 主體主機的 port 4000 用 -p 對映到 image 內 EXPOSE 的 port 80 :


docker run -p 4000:80 friendlyhello
其中-p  指要做 port mapping , 其中 4000 指 主體主機的 port 位,80 指 container 的 port 位,中間用 : 冒號隔開。按 Ctrl-C 離開container。
OK,那接下來我們用 -d 讓我們的app 在背景執行:


docker run -d -p 4000:80 friendlyhello
然後畫面會出現一長串的 CONTAINER ID,然會就回到你的主體主機畫面。現在,我們剛做的container 已經在背景執行了。你可以用 docker ps 來看看你有那些container 正在執行。


$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED
1fa4ab2cf395        friendlyhello       "python app.py"     28 seconds ago
現在我們可以用 docker stop 來中止我們的程式。


分享你的image

registry 是 repositories 的集合,而repository 是 image 的集合。而 registry 上的 account 可以建立許多的 repository。docker command line interface 指令 就是預設的 docker公用 registry。

如果你己經有了 Docker account, 登入 cloud.docker.com。

docker login
畫面會要求你輸入你在 cloud.docker.com 建立的帳密。
現在,我們就可以上傳我們做的image了。 在我們電腦裡的image 含在 registry 上的 repository 的表示式用 username/repository:tag ,其中 :tag 是選擇性的,但建議還是輸入,一般是用來表示這個image 的版本。

docker tag friendlyhello username/repository:tag

可以上傳了:

docker push username/repository:tag
上傳完之後,我門就可以在任何有裝docker 的電腦上,執行下列指令來啟動 我們剛裝的 image,當然,前題是要能上網。如果你沒下 :tag 指令,那它會找最新的,即它會自動加上 :latest 的tag.
現在,用你的流灠器看一下 localhost:4000 ,看是不是有正確的 hello, World 會出現。

2017年5月8日 星期一

Google Assistant 服務 在 RPi or Mac 上的應用

GooglePi

在網路上看到這篇文章,覺得很有興趣,Google Cloud 提供了$300 鎂 的免費試用,因此可以來試試。原本我還在學習圖型辨識,但我想最近AI 越來越強,自己也不是這領域的專家,與其重新學習去當巨人,不如直接站在巨人的肩頭上,看能不能當個巨人肩頭上的寄生蟲。
這裡有官方網頁的教學說明,更清楚:Overview

照著實作

第一步:啟動你的 RPi3

第二步:在Google Cloud 上設定 Google Assistant API

申請完 Google Clound後,首先新增一個專案
然後在Google Could Platform 上 選取 「API 管理員」裡的 「資訊主頁」
點選 在資訊主頁裡有項 「啟用API」


點選後,它會跳到 「API管理員」的 「資料庫」頁面,在搜尋欄裡,輸入「google assistant」,就可以看到 Google 自動幫你在它提供的100多個API 裡 filte 出來。 直接點選下面 filte 出來的 「Google Assistant API」
會看到頁面上針對 「Google Assistant API」的介紹與說明,然後點選頁面上的「啟用」
上面說明 「Google Assistant API」它使用的是 OAuth 2.0 的方式來存取使用者資料,因為它需要存取我們輸入給它的語音資料,因此需要授權。
點選 「OAuth 同意畫面」,如果沒有這個畫面,那先點選到「資料庫」,再點選「憑證」,應該就會有了。

點選「建立憑證」裡的 「OAuth 用戶端ID」
選擇「其它」,名稱用 google-assistant-rpi3, 或你自己取一個。
然後按 「建立」。

你應該就會得到下列畫面:
按下「確定」後,就可以看到你新建立的憑證。

然後點選右方的下載,將憑證存到你的電腦上。

至此,在google 的部分就設定完成了。

第三步:在RPi 上設定 Google Assistant(不過我是在Mac上設定)

首先設定 Python 的 虛擬環境。真的很神奇,現在連程式語言都提供虛擬環境讓你測試,避免像我這種初學者把環境弄得亂七八糟,搞不回來。虛擬環境搞亂了,就刪掉重來就好。

在mac 下,用home-brew 下載 portaudio 模組
然後啟用python虛擬環境,我用的是 virtualenv , 你可以看到 它會新建立一個叫 myenv 的環境:



之後就可以啟動我們的虛擬環境了⋯⋯

你會看到前面的提示符號多了一個 (myenv),即表示我們已經進入虛擬環境內。
接下來就可以安裝 Google Assistant SDK

切換到 ./myenv/bin 下,可以看到已經有兩個googlesamples 的 程式:

googlesamples-assistant 和 googlesamples-assistant-auth

同時把剛才的憑證一併copy 到這裡來
接下來,我們要用 googlesamples-assistant-auth 程式來先做憑證認證。

你會發現程式少了 google.auth 模組,再安裝 google.auth 模組:

再驗證一次憑證:
又少了 requests 模組,再來裝 requests 模組:
再驗證一次憑證:
還少了 google_auth_oauthlib 模組⋯⋯
再來裝 它 :
再驗證一次憑證:
還是少了 click 模組⋯⋯
再來裝它:

再驗證一次憑證:

你的browser 會跳出驗證的確認畫面:

點選你要啟用的帳號,然後再「同意」即完成認證。

Browser 畫面會變成:

同時  terminal 會回到提示符號。
差不多,我們就可以試試看,記得將你的RPi或電腦接上麥克風和喇叭。
然後執行 googlesamples-assistant:

唉⋯⋯還是少了 tenacity 模組,再來裝一下:
再來執行 googlesamples-assistant:
又少了 sounddevice 模組,相信我,這是最後一個我們缺的模組了⋯⋯

用力給它執行下去吧 googlesamples-assistant:

哈哈哈哈⋯⋯
終於可以囉~
這時,你只要按下 「enter」,然後對著Mic 說你要問的東西,Google Assistant 就會從喇叭回應囉⋯⋯可惜的是,它並不懂台語或中文。
至此己完全成功,如果你聽到它回應:
“Actually there are some basic settings that need your permission first. Just go into the Google Home app for details.”
那表示你的 google 帳號並沒有授權google 取用你的「聲音和語音活動」的權限,連到 Google Account Activity Controls 去啟動,就可以正常了。


謝謝參與。

2017年5月4日 星期四

Python 初學

拜讀完 Swaroop C.H 的  A Byte of Python,終於對Python 有個更精確的認識。
以前對 Object Oriented 的概念總是很模糊,但看過他的說明之後,終於了解class 和 object 的關係;了解 __init__ 的用途。
特別寫了封mail 感謝他。

有趣的是,越來越多的開放書,直接就放在GitBook 上,開放式的學習,應該會讓更多人可以無償地吸收新知吧。

感謝世界上無數貢獻知識的人們。

接下來可能會朝Django 學習爬文,或 Google cloud platform 直接用圖形辨識吧。
但還要準備一份 Docker 的簡介,唉~學海無涯啊~


來自 Swaroop 的回信:
Hi Andy!

Thank you for your email. I'm glad the book was useful for you! Thank you for your detailed feedback :)

Hope you continue your Python journey with resources such as:

- Hitchhiker's Guide to Python - http://docs.python-guide.org/en/latest/

Happy programming!

Regards,
Swaroop

On May 2, 2017, at 10:44 AM, Andy Hone  wrote:

Hi, Swaroop:
Thanks for your book that I do really learned something about Python. 
I leant C and basic.(woo, it is really many years ago)
and now I restart to learn a new program.
Though I’ve learned some from the official web site of Python,
But it is really not a good script for a newbie.
I am really thank for your guide that makes me understanding the OO.
I heard Class, Object something else, but I am always confused with them.
Now I finally understand it and I now know what does double underscore really means.
I am really appreciate for what u do and what u share.
Thanks.


Andy Hone

2017年5月3日 星期三

Docker 學習筆記 - Part 1



OS:macOS Sierra

Docker for Mac : Docker for Mac is a complete development environment deeply integrated with the MacOS Hypervisor framework, networking and filesystem. 


get started with Docker :  

事前準備:

請先了解何謂Docker, 你要用Docker 做什麼,然後再開始學習會比較有意義。
當然,最好先有這些基礎:

  • IP address and Ports
  • Virtual Machine
  • 編輯 config file的能力
  • 基本對 程式碼的相依性的與建立程序 的了解
  • 電腦的資源用語,如CPU%,RAM在byte量的使用等等。

Containers的基本介紹:

image (俗稱印象檔)是個輕量化的,獨立的,可執行的套件,其包含了一支小程式所需執行的所有相關程式,包括程式碼,執行序,函式庫,環境變數和設定檔等等。
container 則是一個image 的執行實體,也就是Image 放到記憶體裡實際執行,而不是磁碟裡的檔案而己。而且它是在與主體主機環境完全隔離的環境下執行,只可以在有設定的情況下可以存取主體主機的檔案和port 位。

Container 執行基於主體主機核心(kernel) 的原生應用程式。因此它的效能會比在虛擬主機上的應用程式來得好。Container 可以取得原生的存取功能,而不用透過虛擬主機,每個執行的程式也有其程式序,而不用消耗多餘的資源。