自己建立映像檔 === (last update:2011/11/04) ## 映像檔怎麼來的 映像檔有兩種,一種稱之為base image,就是從什麼都沒有開始的。另一種稱之為normal image,就是由一個base image開始建立的。通常在docker中,90%的映像檔都是normal image。 ### base image 由於docker是一個作業系統等級的執行技術,因此在執行時,作業系統等級的核心功能都已經存在,因此只要你的程式可以在這個作業系統等級的層次執行,就可以成為一個base image **示範建立base image** 1. 建立目錄 ```shell= mkdir baseImageTest cd baseImageTest ``` 2. 建立一個`.cc`語言的檔案,`hello.cc`,內容如下: ``` vi hello.cc ``` ```c++= #include<iostream> using namespace std; int main(){ cout << "Hello! This message is coming from a container \n "; return 0; } ``` 3. 編譯檔案成為Linux的執行檔: ```shell= g++ -o hello -static hello.cc ``` 4. 試執行這個檔案 ```shell= (joshhuAI)joshhu:temp/ $ ./hello [1:43:39] Hello MUST! This message is coming from a container% (joshhuAI)joshhu:temp/ $ ``` 5. 建立`Dockerfile`: ```shell= vi Dockerfile ``` ```dockerfile= FROM scratch ADD hello / CMD ["/hello"] ``` 6. 建立映像檔: ```shell= (joshhuAI)joshhu:temp/ $ docker build -t baseimagetest . [5:51:17] Sending build context to Docker daemon 3.227MB Step 1/3 : FROM scratch ---> Step 2/3 : ADD hello / ---> Using cache ---> ae9b57cf9feb Step 3/3 : CMD ["/hello"] ---> Using cache ---> 2902c1650737 Successfully built 2902c1650737 Successfully tagged baseimagetest:latest (joshhuAI)joshhu:temp/ $ ``` ```shell= (joshhuAI)joshhu:temp/ $ docker image ls [5:52:04] REPOSITORY TAG IMAGE ID CREATED SIZE baseimagetest latest 2902c1650737 5 minutes ago 2.18MB newimage latest f3f53b1d9467 4 days ago 472MB joshhu/test-php-site latest 82d82837d589 4 days ago 472MB test-php-site latest 82d82837d589 4 days ago 472MB php 8.0-apache 3249ab66a0fd 13 days ago 472MB php latest dae5324f443c 13 days ago 476MB ubuntu latest ba6acccedd29 2 weeks ago 72.8MB nginx latest 87a94228f133 3 weeks ago 133MB dorowu/ubuntu-desktop-lxde-vnc latest 1a89db715923 7 months ago 1.32GB tutum/apache-php latest 2e233ad9329b 6 years ago 245MB (joshhuAI)joshhu:temp/ $ docker image history baseimagetest [5:52:06] IMAGE CREATED CREATED BY SIZE COMMENT 2902c1650737 5 minutes ago /bin/sh -c #(nop) CMD ["/hello"] 0B ae9b57cf9feb 6 minutes ago /bin/sh -c #(nop) ADD file:aa3c0bcf6493128bd… 2.18MB (joshhuAI)joshhu:temp/ $ [5:52:16] ``` 7. 執行映像檔成為容器: ```shell= (joshhuAI)joshhu:temp/$ docker run baseimagetest [5:57:44] Hello MUST! This message is coming from a container% (joshhuAI)joshhu:temp/$ ``` ### normal image 從別的docker image繼承而來,再加上自己需要的東西,新成新的image。也可以從現有的container來生成image。 **示範:現在container使用`docker commit`產生image** 1. 啟動一個容器並進入 ```shell= docker run -it busybox ``` 2. 進入後,建立一個文字檔: ```shell= echo 'hello must' > abc ``` 3. 啟動另一個terminal,並且將這個執行中的容器存成新的映像檔: ```shell= (joshhuAI)joshhu:~/ $ docker ps [18:03:05] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 38dbfde45d94 busybox "sh" 33 seconds ago Up 33 seconds kind_northcutt (joshhuAI)joshhu:~/ $ docker images [18:03:06] REPOSITORY TAG IMAGE ID CREATED SIZE baseimagetest latest 2902c1650737 12 hours ago 2.18MB joshhu/test-php-site latest 82d82837d589 4 days ago 472MB test-php-site latest 82d82837d589 4 days ago 472MB busybox latest cabb9f684f8b 7 days ago 1.24MB php 8.0-apache 3249ab66a0fd 13 days ago 472MB php latest dae5324f443c 13 days ago 476MB ubuntu latest ba6acccedd29 2 weeks ago 72.8MB nginx latest 87a94228f133 3 weeks ago 133MB dorowu/ubuntu-desktop-lxde-vnc latest 1a89db715923 7 months ago 1.32GB tutum/apache-php latest 2e233ad9329b 6 years ago 245MB (joshhuAI)joshhu:~/ $ docker commit 38dbfde45d94 newimage [18:03:18] sha256:ab12cc4cf1cfb1ff7f1c0098ee4ae6a0ada31a49696237b758258ec3ca9048de (joshhuAI)joshhu:~/ $ docker images [18:03:31] REPOSITORY TAG IMAGE ID CREATED SIZE newimage latest ab12cc4cf1cf 2 seconds ago 1.24MB baseimagetest latest 2902c1650737 12 hours ago 2.18MB joshhu/test-php-site latest 82d82837d589 4 days ago 472MB test-php-site latest 82d82837d589 4 days ago 472MB busybox latest cabb9f684f8b 7 days ago 1.24MB php 8.0-apache 3249ab66a0fd 13 days ago 472MB php latest dae5324f443c 13 days ago 476MB ubuntu latest ba6acccedd29 2 weeks ago 72.8MB nginx latest 87a94228f133 3 weeks ago 133MB dorowu/ubuntu-desktop-lxde-vnc latest 1a89db715923 7 months ago 1.32GB tutum/apache-php latest 2e233ad9329b 6 years ago 245MB (joshhuAI)joshhu:~/ $ ``` 4. 從這新的映像檔生成一個新容器,並觀察新容器原來的檔案系統中就已經有剛才新建的`abc`這個檔案了。 ```shell= (joshhuAI)joshhu:temp/ $ docker run -it newimage [19:47 / # ls abc bin dev etc home proc root sys tmp usr var / # cat abc hello must / # ``` ## `Dockerfile`詳解 ### 什麼是`Dockerfile` 用來建立normal image的一個設定檔,使用這個`Dockerfile`建立的映像檔可以產生container。產生的container分為一次性及能長期提供服務的`automated`兩種。主要的差別就是`automated`的容器其映像檔在建立時,有提供一個`CMD`指令讓服務常駐,其它就是在建立映像檔時加入檔案、目錄,以及執行什麼Linux程式的指令了。 ### 如何建立映像檔 * 手動建立一個`Dockerfile`,大小寫要完全一樣 * 為`docker build`的設定檔 * 類似一個批次檔,純文字 * Docker系統會照著檔案中的每一個**指令**來建立不同的layer * 建立完這個layer後就寫死,進入下一個layer * 因此會不斷產生舊layer(唯讀),新layer(可寫) * 最執行完最後一個layer時,會清掉中間的暫存layer,成為一個完整的Image * 整個Dockerfile的過程,就是不斷建立layer的過程 ### `Dockerfile`說明 * `#`開頭的為註釋,為說明資訊,如使用方式 * `FROM`:基底映像檔資訊,從哪個Image為基礎建立,使用`scratch`就不引用別人的映像檔 * `MAINTAINER`:建立者 * `RUN`:執行程式 * `VOLUME`:掛載卷冊 * `EXPOSE`:開放通訊埠 * `ADD`:將主機資料加入映像檔 * `ENV`:傳遞參數到外面的世界,可由`docker inspect`取得 * `CMD`:容器啟動時指令,通常為`.sh`指令檔,通常只有一項。**注意:此.sh的執行環境是在容器內,執行該sh的bash不會察覺外部的主機** **注意:如果你引用的映像檔已經有`CMD`指令,並且也開放了通訊埠,你的新映像檔可以不加`CMD`及`EXPOSE`,將會沿用舊的。** ### `Dockerfile`注意事項 * 使用方式:`docker build -t=<映像檔標籤> .` * 例:`docker build -t=“joshhu/buildtest:v1" .`` * 每一條指令會建立一個容器 * 每一條指令完成,其實就執行`docker commit` * 全部執行完,傳回最後一個image id * 中間所有的layer都會被刪除 * 每個`docker bulid`的映像不可超過127層 ## 示範如何佈署一個網站() ### 一、註冊docker hub帳號 1. 來這邊註冊https://hub.docker.com/ 2. 註冊之後必須本機登入 ```shell= docker login ``` ### 二、在本機建立一個`Dockerfile` 建立一個目錄。 ```shell= mkdir docker_test cd docker_test mkdir src/ ``` 建立一個`php`檔案 ```shell= vi index.php ``` 以下是`index.php`的內容: ```php= <html> <h1>Hello Must</h1> <?php $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://ipinfo.io/"); curl_exec($ch); $ip = curl_getinfo($ch,CURLINFO_PRIMARY_IP); curl_close($ch); echo $ip; ?> <img src='src/benz.jpg'> </html> ``` 建立一個`info.php` ```shell= echo "<?php phpinfo(); ?>" > info.php ``` 建立一個`Dockerfile` ```shell= vi Dockerfile ``` ```dockerfile= FROM php:8.0-apache WORKDIR /var/www/html RUN apt update -y RUN apt upgrade -y COPY index.php index.php COPY info.php info.php COPY src/ src EXPOSE 80 ``` ### 三、建立本機`image` 建立映像檔 ```shell= docker build -t my-php-site:latest . ``` 用這個映像檔啟動一個容器 ```shell= docker run -d -p 80:80 my-php-site ``` ### 四、在本機登入`docker login` 先要註冊一個docker hub的帳號密碼 http://hub.docker.com 回到主機,登入 ```shell= (joshhuAI)joshhu:docker_test/ (main✗) $ docker login [23:12:50] Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: joshhu Password: WARNING! Your password will be stored unencrypted in /home/joshhu/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded ``` ### 五、將本機`image`將上tag,丟上docker hub ``` docker tag test-php-site joshhu/test-php-site docker push joshhu/test-php-site ``` ### 六、在production server上佈署程式 1. 先登入到新的伺服器器上,確定安裝好`docker`,並且`docker login`完成。 2. 直接執行程式 ```shell= docker run -d -p 80:80 joshhu/test-php-site ``` 就可以在production server上看到程式執行起來了。 ###### tags: `docker`