2015年6月9日 星期二

Docker - 建立CentOS的OpenSSH Server映像檔


目標: 以CentOS 7為基礎,在其上建立一層OpenSSH-Server服務
環境: 在Linux環境上安裝Docker完成

1.從預設的倉庫(Docker Hub) pull下CentOS的基礎映像檔

# docker pull centos
執行docker images應該會看到repository欄位有個名為docker.io/centos、TAG為latest的image


2.以centos image開啟一個container 並進入容器內

# docker run -t -i --name ssh-server centos /bin/bash
執行後進入了container內的bash介面
參數-t:Docker 分配一個虛擬終端機綁定在container的STDIN
參數-i:使container的STDIN保持開啟(即便沒有 attach) 在Container執行ps會發現只有ps和/bin/bash兩個程序在執行,純粹只有看得到我們在container內所啟動的程序,實踐了程序隔離的功能,有關其原理,參考docker 原理簡介
在本地端下docker ps命令會看到目前正在執行中的container,多加-a參數則會連停用中的container連帶列舉出來


3.在Container內安裝openssh-server

# yum install openssh-server
(進入container內預設是root使用者)

4.開啟sshd服務

在container內執行systemctl start sshd會遇到這樣的錯誤訊息:
Failed to get D-Bus connection: No connection to service manager
這裡需要澄清的概念為,Docker的container為"應用程式層的container",而非"作業系統層的container",在container這個獨立的程序沙盒內,是沒有辦法存取到系統的systemctl這個程序

那就手動開啟sshd吧!
# /usr/sbin/sshd
結果顯示如下錯誤訊息
Could not load host key: /etc/ssh/ssh_host_rsa_key
Could not load host key: /etc/ssh/ssh_host_ecdsa_key
Could not load host key: /etc/ssh/ssh_host_ed25519_key
原因就是沒有Host key,平時我們以systemctl啟動sshd會先執行/usr/sbin/sshd-keygen -A產生host key,所以此時必須手動產生:
# /usr/sbin/sshd-keygen -A
然後再次執行/usr/sbin/sshd,就可以正常啟動了

5.以netstat檢查是否開啟成功(Check port 22)

# netstat -tunlp
確定有Listen port 22後就是成功執行sshd了

6.匯出成image

使用docker commit指令匯出成一個映像檔
上半部的步驟為手動建立Image,說實話,完全派不上用場
新目標:使用Dockerfile建立SSH-Server的映像檔,且可以透過Port-Forwarding的方式從外部連線進入Container。

0.認識Dockerfile

就我個人的認知,Dockerfile就像是屬於Docker映像檔的腳本,裡面可以定義基於哪一個映像檔、執行什麼指令、使用這個映像檔時會執行什麼事情...等等。詳細的指令寫法可以參考指令| Docker --從入門到實踐
大部分環境的佈置準備都會在Dockerfile內,一層一層第包裝起來。


1.開工,第一個Dockerfile

#Dockerfile跟shell script一樣,使用#當作註解符號

FROM centos:latest
#Dockerfile內第一行皆為宣告從哪一個基礎映像檔開始搭建

MAINTAINER crashedbboy@gmail.com
#標示 author

RUN yum -y install openssh-server passwd
#RUN為在當前映像檔基底上執行命令(此處用法相當於以/bin/sh執行)

RUN echo "root123" | passwd root --stdin
#測試設定root的密碼

COPY run-sshd.sh /run-sshd.sh
#把"Dockerfile當前所在目錄的腳本檔"複製近Image裡面,這個腳本檔目的是用來啟動SSH server

RUN chmod +x /run-sshd.sh
RUN chmod 755 /run-sshd.sh
RUN /usr/sbin/sshd-keygen -A

EXPOSE 22
#設定對外的Port

CMD ["/run-sshd.sh"]
#建立好的Image被執行時,會自動執行的動作,這裡設定成一旦run這個映像檔,就會執行腳本啟動SSH服務


2.啟動SSH Server的腳本檔

歷經波瀾後,回歸"一個容器執行一個服務"的精神...
#!/bin/bash
/usr/sbin/sshd -D
-D參數使得sshd不會變成在背景執行的Daemon,原因將在其後說明


3.建立映像檔

# docker build -t username/image-name "Dockerfile所在目錄"
docker會在該目錄下搜尋是否有檔案名為"Dockerfile",如果找到就開始建立映像檔了
建立過程中,Dockerfile內每一行都會視為一個Step,並把執行結果噴在終端機上給我們欣賞

4.開啟映像檔

# docker run -d -p 2000:22 --name sshd Image名稱
-d:在背景執行
-p:在Host與container之間做Port-Forwarding
--name:命名Container
因為此映像檔在啟動時就會自動執行run-sshd.sh這個腳本,所以Docker run就不再設定執行的動作給Container,否則之前設定的動作會被覆蓋掉

附錄. 成功背後的腥風血雨

初次使用Dockerfile製作映像檔的時候,把CMD宣告的啟動腳本內寫入多個動作,除了啟動ssh daemon之外,最後一行還執行了Bash,這樣導致的結果就是每次Docker run -d開啟這個映像檔時,因為沒有attach進Container的Bash,容器內的任務就算是執行結束了,使用Docker ps 總是會看到容器處於Exit的狀態,Port-Forwarding自然也關掉了。
原本的自啟動腳本:
#!/bin/bash
/usr/sbin/sshd-keygen -A
/usr/sbin/sshd
# 沒有加-D參數的話預設是丟到背景執行

/bin/bash
# 錯在這裡


參考資料

Docker官方使用手冊
《Docker —— 從入門到實踐­》正體中文版
Docker原理簡介