【黑科技回憶童年】用Docker玩轉神奇寶貝!
這個畫面懷念嗎?現在就教你如何用docker玩轉神奇寶貝!
項目實戰
原項目簡介
weplay是一個socket.io庫的展示項目,你可以在socket.io官網的展示頁面看到它。它是由socket.io庫的開創者rauchg,將一個已有的用Javascript實現的GBC模擬器,包裝成一個Node.js模塊后,再運用socket.io和HTML5的畫布API,用Redis作為數據中轉以及持續化存儲的一個中型項目。
准備工作
1.項目總覽:
-
weplay作為IO服務器,提供評論數據的持續化儲存和實時GBC界面數據的輸出服務。
-
weplay-web提供網頁服務。
-
weplay-emulator運行js模擬器,將數據渲染出的每個畫面輸出到Redis中。
-
weplay-presence用socket.io接口統計實時在線總人數。
項目已經被很明確的分割成了幾個模塊,由后台服務器鏈接起來。
2.數據庫的加密加固工作:
由於此項目之前的架構大概是一體化,單一服務器的部署思路。Redis數據庫端沒有做加密訪問。但是我們都知道,Redis是很容易被破解的,它的快速是把雙刃劍。如果我們在此添加訪問受密碼保護的Redis服務器的代碼,那么我們的服務就算是在某些危機四伏的彈性雲平台上也能很好的運作。 所以對於所有模塊進行打補丁。
3.與容器化無關的功能增加與版本更新
-
如添加彈幕模式
-
優化模擬器運行效率和內存占用
-
可由環境變量方便的選擇加載的游戲ROM
容器化核心:Dockerfile編寫
1.首先給個具體的實例,是weplay-web,項目網頁服務器的容器化Dockerfile。
FROM node:0.10
MAINTAINER Jiahao Dai <dyejarhoo@gmail.com>
RUN git clone https://github.com/imdjh/weplay-web /srv/weplay-web && \
cd /srv/weplay-web && \ npm install && \ npm install forever -g
ADD docker-entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 3000
CMD ["/entrypoint.sh"]
實際上編寫Dockerfile很簡單,不外乎幾個步驟:
-
FROM宏,用來指定基礎鏡像,docker的應用鏡像都是有層級的,可以復用造一個輪子不用從砍大叔開始;
-
MAINTAINER,用來告訴使用者這個鏡像有問題該找誰;
-
RUN,你希望鏡像在被構建(build)時,執行什么命令,在這里我們用git工具下載最新的源代碼並用npm安裝依賴;
-
ADD,你希望將什么文件復制到容器中;
-
EXPOSE,你希望容器的哪些端口對外開放;
-
CMD,有哪些命令(如果是指令,一定主意路徑要在PATH環境變量中)是需要在容器初始運行時作為進程PID1存在的(當ENTRYPOINT為空時)。
和幾個注意點:
-
每個Dockerfile中的宏指令會生成一個鏡像層(image layer),所以最好在執行命令的時候,最后要回收垃圾,這樣執行完這條宏,生成的鏡像層會比較輕巧。例如這條語句:RUN apt-get update && apt-get install -y libcairo2-dev && rm -rf /var/lib/apt/lists/*,就做到了最小化安裝一個軟件源里的二進制包。
-
將守護進程寫在單一的文件中,例如本項目中的docker-entrypoint.sh。方便拓展和日后修改。
docker-entrypoint.sh的一般編寫思路
-
設置默認環境變量的值
-
當某些環境變量未被設置時,進入出錯模式,自動退出執行。
-
執行守護進程
例如letweplay的入口腳本:
#!/bin/bash
# 設置環境變量export
WEPLAY_WEB_PORT=3000
export WEPLAY_IO_URL="${IO_URL_PORT:-BAD}"
export NODE_ENV='production'
if [[ -n "${REDIS_PORT}" ]];then export WEPLAY_REDIS_URI=${REDIS_PORT_6379_TCP_ADDR}:${REDIS_PORT_6379_TCP_PORT} # 當某些環境變量未被設置時,進入出錯模式,自動退出執行 export WEPLAY_REDIS_AUTH=${REDIS_PASSWORD}else echo "Redis setting not found, can't start server." >&2 && exit 1
fi
if ( $(echo ${WEPLAY_IO_URL} | grep -q BAD ) );then echo "IO_URL_PORT is missing, can't start entry server." >&2 && exit 1
fi
# 執行守護進程
forever /srv/weplay-web/index.js
容器化實現
1.Docker Compose方案
感謝compose工具,否則部署一個多模塊的項目會是讓人頭疼的一件事。 這里選用靈雀雲平台http://www.alauda.cn/,采用靈雀雲的開源命令行工具alauda,支持compose部署,可以做到多模塊的項目一鍵部署在靈雀雲平台。對於本項目來說我們可以按照下面的步驟迅速布置起來一個平台環境。
-
首先使用python2的pip工具,下載安裝alauda工具。注意python3環境下,此工具會報錯不能正常使用。
-
然后,登陸進入自己的賬號,進行日后API調用的Oauth審核。
-
將如下yml格式的內容保存成my.yml
core: image: 'index.alauda.cn/imdjh/letweplay-core:fallback' environment: - GAME=pokemon/yellow - SAVEDELAY=120000 - WEPLAY_REDIS_AUTH=rosebud links: - redis size: 'XS' entry: image: 'index.alauda.cn/imdjh/letweplay:latest' environment: - 'IO_URL_PORT=http://io-imdjh.myalauda.cn' - 'WEPLAY_REDIS_AUTH=rosebud' - 'THIS_URL_PORT=http://entry-imdjh.myalauda.cn' - WEPLAY_WEB_PORT=80 links: - redis ports: - 80/http restart: on-failure size: 'XXS' io: image: 'index.alauda.cn/imdjh/letweplay-io:latest' environment: - 'THIS_URL_PORT=http://io-imdjh.myalauda.cn' - 'WEPLAY_REDIS_AUTH=rosebud' links: - redis ports: - 3001/http size: 'XXS' redis: image: 'index.alauda.cn/library/redis:latest' size: 'XXS' ports: - 6379/tcp volumes: - /data:10
-
再運行alauda compose up -f my.yml,等待出現諸如:
$ alauda compose up -f my.yml [alauda] Creating and starting service "redis"
[alauda] Creating and starting service "core"
[alauda] Creating and starting service "io"
[alauda] Creating and starting service "entry"
[alauda] OK
-
因為redis在啟動后需要一定時間才能開始監聽端口,而鏈接到的各容器會不能立即接連到數據庫而出錯。所以我們需要使用如下指令手動重啟容器,由於它們並不存有數據,所以重啟是無害的。
$ alauda service stop io && alauda service start io $ alauda service stop entry && alauda service start entry $ alauda service stop core && alauda service start core
-
既然用了有狀態的容器,那么就對數據庫做一個存檔吧,靈雀雲可以很方便地進行存儲卷備份:
$ alauda backup create redis-$(date +%F) redis '/data'
[alauda] Creating backup "redis-2015-11-30"
[alauda] OK
2.單個擊破-單個部署方案:如果出於種種原因沒辦法安裝compose工具,那么我們也能一條條的docker run起來:
$ #跑一個Redis容器,命令為some-redis
$ sudo docker run --name some-redis -d redis $ #跑個GBC模擬器,鏈接到some-redis
$ sudo docker run -d -e 'GAME=pokemon/yellow' --link some-redis:redis imdjh/letweplay-core $ #Socket.io服務器開起來,鏈接到some-redis
$ sudo docker run -d --link some-redis:redis -e 'THIS_URL_PORT=http://localhost:3001' -p 3001:3001 imdjh/letweplay-io $ #開啟萬維網服務器,鏈接到some-redis,服務已經全部開啟!
$ sudo docker run -d -e 'THIS_URL_PORT=1.2.3.4:3000' -e 'IO_URL_PORT=1.2.3.4:3001' --link some-redis:redis -p 0.0.0.0:3000:3000 imdjh/letweplay
3.圖形化操作方案:如果你更習慣圖形化界面的操作,可以在靈雀雲控制台中,由redis, letweplay-core, letweplay-io, letweplay的順序進行服務的創建。
本實例一共使用了4個容器。配置如下:
-
3台XXS(256 MB)的容器分別運行:letweplay, letweplay-io, redis
-
1台XS(512MB)的容器運行:letweplay-core
部署的配置參數可以用如下截圖作為參考:
-
數據庫redis部分
-
IO服務器letweplay-io部分
-
模擬器服務器letweplay-core部分
演示地址:lwp-entry-imdjh.myalauda.cn
怎么樣?很酷吧!
最近發現docker在游戲開發運維中還是有不少好處滴,希望和游戲圈的諸位同好共同交流,玩轉docker這個大火的技術,下面是一個技術交流群,感興趣的朋友可以微信掃一掃,共同探討