docker container測試flask,無法於外部Host瀏覽

 我用Docker來測試及學習Flask,container有將Port mapping:5000:5000

test.py的內容如下,是一段簡單的程式:

from flask import Flask

app = Flask(__name__)

@app.route("/")

def hello_world():

    return "<p>Hello, World!</p>"

if __name__ == "__main__":

    app.run(debug=True, host='0.0.0.0', port=5000)

因為在討論區上有人提到flask預設會只能使用localhost,所以我有加上host='0.0.0.0'

接著我執行下列的指令來啟動Web Server:

# export FLASK_APP=test

# flask run


在docker container用crul http://127.0.0.1:5000來測試,有正確出現Hello,World的訊息。

但是在Host端用瀏覽器開啟http://192.168.1.1:5000(192.168.1.1是Host的IP)卻無法顯示網頁。


接著在討論區上又看到有人提到新版本要以python加參數來啟動flask,所以我依樣輸入下列指令:

# export FLASK_APP=test

# python3 -m flask run --host='0.0.0.0'


再次以瀏覽器開啟http://192.168.1.1:5000,這次就正確出現Hello,World

docker container出現Operation not permitted的錯誤

 我在Windows 10有安裝docker並自訂一個image,後來將這個image移轉至Linux上後產生新的container

在這個container上執行 ls -lh的指令時,卻出現了下列的錯誤,Windows上的container並此錯誤,而且還是以root的身分。

root@3c68aa381e26# ls -lh
ls: cannot access 'prtg_uwsgi.sock': Operation not permitted
total 0
s????????? ? ? ? ?            ? prtg_uwsgi.sock

在google查找一下原因,發現是linux核心中有支援seccomp的緣故。所以不只是ls,還有許多的指令都會出現Operation not permitted

seccomp(secure computing mode,安全計算模式)可以用來限制容器內可用的操作。
預設的seccomp配置為容器提供了一個合理的設定,並且禁用許多的系統呼叫。它具有適度的保護性,同時提供廣泛的應用相容性。
更詳給的內容可以參考:https://docs.docker.com/engine/security/seccomp/

所以Linux為了讓Docker更加安全,所以限制了container部份的權限,就算是以root身份來執行,該限制依舊是有效的。

檢查系統是否有支援secomp:
# grep CONFIG_SECCOMP= /boot/config-$(uname -r)
CONFIG_SECCOMP=y


那如果我們有需要這些被限制的功能,則有幾種方式可以放寬限制:

1、使用privileged來啟用特權容器(privileged container),即可取得最大的權限
# docker run --privileged <image>


2、關閉seccomp
docker run --security-opt seccomp=unconfined <image>


3、放寬部份的限制,這是建議的方式,只開放有需要的權限,可參考https://docs.docker.com/engine/security/seccomp/

例如文件中關於修改系統時間的說明如下:
settimeofday Time/date is not namespaced. Also gated by CAP_SYS_TIME.
stime Time/date is not namespaced. Also gated by CAP_SYS_TIME.

我們就可以將CAP_SYS_TIME加入白名單中,以解除此限制(會自動加上cap_,所以只需要指定sys_timem關鍵字),如下所示:
# docker run --cap-add SYS_TIME <image>

Flask + uWSGI + Nginx架設記錄

我有一支用Python開發的http api程式,是以http.server的module啟動service,但是這僅適合測試環境使用。

後來我把Python改以Flask開發,但是Flask預帶的Web Service也不被建議用在正式環境上。

所以最後我用Flask + uWSGI + Nginx來完成正式環境的架設,記錄一下以免之後忘記了。

安裝Flask、uWSGI、Nginx程式,我的作業系統是ubuntu

# apt install nginx
# pip3 install Flask
# pip3 install uwsgi

我的測試Flash程式,檔名server.py,內容如下:

from flask import Flask
app = Flask(__name__)
@app.route("/")
def test():
    return "相思樹下數相思,怨君不知相思苦"
if __name__ == '__main__':
	app.run()

啟動flask服務,利用curl http://127.0.0.1:5000來看看是否有傳回「相思樹下數相思,怨君不知相思苦」

# python server.py


uWGI可以使用三種協定設定,而nginx則必需配合uWGI的協定來配置

1、socket協定

------------------

uWSGI設定,新增一個配置檔,如uwsgi_test.ini

[uwsgi]
module			= server:app
chdir			= /test_flask
master			= true
processes		= 3
socket			= /var/run/test_uwsgi.sock
die-on-term		= true
chmod-socket	= 666
logto			= /var/log/uwsgi_test.log

moule是設定flask的檔案(不用加.py)及入口程序名,以測試檔server_flask.py而言是指app

chdir是flask程式的路徑

processes是指定uWGI要啟用多少個process

socket是設定scoket的檔案位置,nginx與uWGI依靠這個檔案相互搭起

chmod設定權限,我有試過設定660,結果造成nginx無法讀取socket檔案

logto是設定log的目錄

nginx設定,在/etc/nginx/sites-available內新增配置檔,如webtest.conf

server {
    listen      80;
    charset     utf-8;

    location / {
        try_files $uri @app;
    }
    location @app {
        include     uwsgi_params;
        uwsgi_pass  unix:/var/run/uwsgi_server.sock;
    }
    location /test {
        default_type "text/html";
        alias /html/test01.html;
    }
	location /js {
	    alias /html/js;
	}
}   


2、http協定

-------------------------

uWSGI 配置:

[uwsgi]
wsgi-file = /test_flask/server.py
callable = app
http= :8000
processes = 3
threads = 2
master = true
chmod-socket = 660
vacuum = true
die-on-term = true


wsgi-file是flask的完整檔名



Nginx 配置:

server{
    listen  80;
    location /{
        proxy_pass  http://127.0.0.1:8000;
    }
}


3、uwsgi協定

--------------

uWSGI 配置

[uwsgi]
wsgi-file = server.py
callable = app
socket = :8000
processes = 4
threads = 2
master = true
chmod-socket = 660
vacuum = true
die-on-term = true


Nginx 配置

server{
    listen  80;
    location /{
        include uwsgi_params;
        uwsgi_pass 127.0.0.1:8000;
    }
}


啟動uWSGI、nginx:

# uwsgi test.py
# nginx


利用curl http://127.0.0.1來看看是否成功傳回「相思樹下數相思,怨君不知相思苦」

cx_oracle error: 找不到libclntsh.so

今天在以Python + cx_oracle來連接Oracle DB時出現下列的錯誤,而我已經有設定正確的LD_LIBRARY_PATH:

cx_Oracle.DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library: "libclntsh.so: cannot open shared object file: No such file or directory"

原來這個libclntsh.os是作業系統缺少了某個套件libraio1,因為我的是Ubuntu,所以輸入下列指令來安裝:

# apt-get install libaio1

安裝完後,再次測試就沒有問題了。


利用Chrome DevTools自動輸入測試資料

 我有一個網頁程式是新增資料用的,當測試時都需要自己key測試資料,文字欄位一多,測試次數又多,是很累人的。

當然有許多的方法及軟體都可以做到這樣的事情,而且功能更加強大。不過我試著用Chrome Developer Tools來嘗試。因為有試出來,故記錄下來。

網頁如下圖,有一些文字欄位要輸入,而且都是必填的欄位



首先找出元素的Selector路徑,按F12開啟Chrome DevTools,選擇網頁上的元素並按下滑鼠右鍵選擇「檢查」

接著Chrome就會在DevTools的Elements頁面反白出元素的html原始碼,在反白的元素原始碼按下滑鼠右鍵,選擇「Copy」-> 「Copy JS path」,如下圖


例如找出來的Selector Path如下:document.querySelector("#itemID")

在DevTools的Console頁面輸入document.querySelector("#itemID").value='1001',這樣網頁上的文字欄位就自動填上測試值了,如下圖:



只要重覆找出需要輸入的元素後,把它全部集中在一起,之後利用複製貼上就可以一次讓網頁上的欄位都自動填上測試資料。

離線移轉docker images到其他的docker server上

 通常都是直接由網路上下載images,但是現在有一台docker伺服器是無法連網。


所以先在可以上網的Docker伺服器上先下載好images,再執行下列指令將images匯出來

# docker save -o helloworld.tar helloworld

參數 -o 後面接的是匯出來的檔案名稱


將匯出來的helloworld.tar上傳到另一台伺服器,再執行下列指令匯入

# docker load -i helloworld.tar

參數-i是要import的檔案名稱


這樣就完成兩台之間images的移轉了。

Centos 7.9離線安裝Docker

 今天將Docker裝好了,記錄一下,以免之後又忘了

1、下載container-selinux-2.9-4.el7.noarch.rpm、docker-ce-17.12.0.ce-1.el7.centos.x86_64.rpm並上傳到伺服器

2、執行安裝,因為有依賴性問題,所以要注意這個package要先安裝

# yum localinstall -y container-selinux-2.9-4.el7.noarch.rpm

3、再安裝下一個package

# yum localinstall -y docker-ce-17.12.0.ce-1.el7.centos.x86_64.rpm

5、啟動Docker服務

# systemctl  start  docker

6、下載一個示範image來驗證是否正常

# docker run hello-world