一個全新的開發體驗
在過去的時候,如果你想運行一個Java
的app,你首要的事情就是安裝一個Java
的runtime
(也就是JDK),但是就是在這一步一般都有很多問題。首先你要保證你安裝的
runtime適配的app所需的環境,而且還要保證適配你的生產環境。可能這是大家都有過的體驗:要跑起來一個java程序,你要去選擇jdk,要去安裝,安裝完了還要去設置JAVA_HOME
。
可能一台機子沒有什么感覺,但是如果有20台機子,上面那些步驟你就要重復20次,而且一般的生產環境更為復雜,不止有Java程序,還有可能有Nginx
,Redis
甚至可能有數據庫。
每次搭建一個項目,你可能就是一次"脫胎換骨"的體驗。
有了Docker,上面的問題就將大大緩解。docker倉庫有很多輕便的,開箱即用的鏡像。現在你運行一個Java
程序只需要將程序運行在這些已經打包好的鏡像就行了,不需要安裝,也不需要關心
JAVA_HOME
的路徑。
而這些鏡像就是被一個叫Dockerfile
的文件定義的。現在這么說可能很籠統,讓我們來實際操作一下,如何將一個程序的runtime
變成一個文本文件。
使用Dockerfile定義一個容器
Dockerfile 是一個用來描述容器內部運行環境的文件,比如網絡接口、磁盤驅動。這些環境和系統其他環境是隔離的。接下里已官網給出的一個例子為列。 官網例子是python的,這里另寫了一個部署java應用的
着手開始
首先創建一個空的目錄,然后在該目錄下創建一個文件,文件名為Dockerfile
(注意文件沒有后綴,首字母要大寫)。
# 創建一個hello的目錄 $ mkdir hello $ cd hello # 創建一個Dockerfile $ touch Dockerfile # 或者 $ vim Dockerfile
將以下的文本內容從復制粘貼到Dockerfile
中:
# 使用官方的鏡像作為父類鏡像 FROM python:2.7-slim # 設置容器的工作目錄為 /app WORKDIR /app # 將當前目錄下的文件拷貝到容器的工作目錄下面 ADD . /app # 執行額剛剛拷貝進來的文件 RUN pip install --trusted-host pypi.python.org -r requirements.txt # 將容器的80端口暴露出來,供容器外部訪問 EXPOSE 80 # 定義環境變量 ENV NAME World # 當容器運行起來時執行使用python運行app.py CMD ["python", "app.py"]
對於app本身
剛剛我們定義一個容器,它僅僅是運行我們app的環境。真正要運行起來的項目的代碼則是需要自己去寫。
看到上面Dockerfile中,發現了兩個之前不知道的文件-- requirements.txt
和 app.py
。這兩個便是我們項目本身。
將這兩個放到和Dockerfile
平級的目錄中,這樣我們通過 Dockerfile
創建容器鏡像時就可以將這兩個文件通過ADD
命令拷貝到容器中。
requirements.txt
:
Flask
Redis
app.py
:
from flask import Flask from redis import Redis, RedisError import os import socket # Connect to Redis redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2) 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)
pip install -r requirements.txt
安裝了
flask
和
Redis
這兩個項目運行時的依賴。然后這個程序就是打印剛剛
Dockerfile
中定義的環境變量
NAME
,並且輸出訪問項目的請求的
hostName
。因為我們只是安裝了python訪問Redis的依賴而不是真的安裝了Redis,所以訪問項目是報錯,這也是期望之中的。
總結:
在整個項目的搭建的過程中,我們並沒有在系統上安裝任何運行時環境,我們沒有關心python在系統的依賴,但是這個程序就能正常跑起來了。如果要移植到
其他機器上面,什么都不用管,只用把Dockerfile
拷貝過去,執行一下,就能快速啟動另一個應用。是不是很方便!
創建鏡像
上面解釋了這個應用的執行過程,接下來說一下如何啟動這個應用。首先運行以下命令創建一個容器鏡像(注意最后那個點,表示當前目錄下):
# -t 給容器取個名字,容器默認名字是none docker build -t friendlyhello .
命令執行完了以后,可以通過以下命令查看剛剛創建的鏡像:
$ docker image ls
運行應用
通過以下命令運行容器,並且將容器的80
端口綁定到宿主機的4000
端口上,這樣外界就可以通過訪問宿主機的4000端口來訪問容器內的應用了:
docker run -p 4000:80 friendlyhello
使容器后台運行:
# -d docker run -d -p 4000:80 friendlyhello
查看容器:
$ docker container ls CONTAINER ID IMAGE COMMAND CREATED 1fa4ab2cf395 friendlyhello "python app.py" 28 seconds ago
停止容器:
# 1fa4ab2cf395 容器的ID docker container stop 1fa4ab2cf395