---
# System prepended metadata

title: 自己建立映像檔
tags: [docker]

---

自己建立映像檔
===
(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`

