關於docker的scratch鏡像與helloworld
參考:https://hub.docker.com/_/scratch?tab=description
參考:https://segmentfault.com/a/1190000000628247
FROM scratch
官方說明:該鏡像是一個空的鏡像,可以用於構建busybox等超小鏡像,可以說是真正的從零開始構建屬於自己的鏡像。要知道,一個官方的ubuntu鏡像有60MB+,CentOS鏡像有70MB+
可以把一個可執行文件扔進來直接執行
一、注意:scratch不可用被pull
FROM scratch專門用於構建最小鏡像,直接pull會報以下錯誤,scratch是一個保留名稱
[root@es-master1 ~]# docker pull scratch
Using default tag: latest
Error response from daemon: 'scratch' is a reserved name
二、如何制作大小為0 的鏡像
既然scratch不能被拉取,如何做到docker image ls
看到一個0字節的鏡像
官方給出了下面方法:
$ tar cv --files-from /dev/null | docker import - scratch
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
scratch latest 775bfce21429 9 minutes ago 0B
三、如何跑一個helloworld
可以參考:https://github.com/docker-library/hello-world/
3.1C語言不行,docker是go語言寫的,跑的話報錯
[root@es-master1 ~]# cat hello.c
#include <stdio.h>
main() {
printf("hello world\n");
}
[root@es-master1 ~]# gcc hello.c -o hello
[root@es-master1 ~]# ll hello
-rwxr-xr-x 1 root root 8440 Nov 21 03:36 hello
Dockerfile
FROM scratch
COPY hello /
CMD ["/hello"]
[root@es-master1 ~]# docker build -t hello .
[root@es-master1 ~]# docker image ls hello
REPOSITORY TAG IMAGE ID CREATED SIZE
hello latest 3b89b5056a03 5 minutes ago 8.44kB
果然報錯
[root@es-master1 ~]# docker run --rm hello
standard_init_linux.go:211: exec user process caused "no such file or directory"
ubuntu當然可以
[root@es-master1 ~]# cat Dockerfile
FROM ubuntu
COPY hello /
CMD ["/hello"]
[root@es-master1 ~]# docker build -t hello .
Sending build context to Docker daemon 24.63MB
Step 1/3 : FROM ubuntu
---> 775349758637
Step 2/3 : COPY hello /
---> 33de2082f11a
Step 3/3 : CMD ["/hello"]
---> Running in 3d347f62b926
Removing intermediate container 3d347f62b926
---> 1829a7bd40fe
Successfully built 1829a7bd40fe
Successfully tagged hello:latest
[root@es-master1 ~]# docker run --rm hello
hello world
官方的這個竟然有點看不懂了,c語言:https://github.com/docker-library/hello-world
[root@es-master1 tmp]# git clone https://github.com/docker-library/hello-world.git
[root@es-master1 tmp]# cd hello-world/
[root@es-master1 hello-world]# make all
[root@es-master1 hello-world]# amd64/hello-world/hello
Hello from Docker!
......
3.2go語言
使用go語言寫:https://github.com/adriaandejonge/helloworld
[root@es-master1 hello-world]# tree -C .
.
├── Dockerfile
└── hello.go
0 directories, 2 files
[root@es-master1 hello-world]# cat hello.go
package main
import "fmt"
func main(){
fmt.Printf("hello world\n")
}
[root@es-master1 hello-world]# cat Dockerfile
FROM google/golang as builder
WORKDIR /go/src/app
COPY hello.go .
RUN go build hello.go
FROM scratch
COPY --from=builder /go/src/app/hello /
CMD ["/hello"]
一個helloworld都這么大...
[root@es-master1 hello-world]# docker build -t hello .
[root@es-master1 hello-world]# docker image ls hello
REPOSITORY TAG IMAGE ID CREATED SIZE
hello latest 27eca431407a 2 minutes ago 2.36MB
[root@es-master1 hello-world]# docker run --rm hello
hello world
[root@es-master1 hello-world]# docker image history hello
IMAGE CREATED CREATED BY SIZE COMMENT
27eca431407a 3 minutes ago /bin/sh -c #(nop) CMD ["/hello"] 0B
1a35249e8575 3 minutes ago /bin/sh -c #(nop) COPY file:7b1994197d7b5310… 2.36MB
也沒用過go,網上了解到加個選項就能變小:https://www.jianshu.com/p/1405b0c2c5a3
[root@es-master1 hello-world]# cat Dockerfile
FROM google/golang as builder
WORKDIR /go/src/app
COPY hello.go .
RUN go build -ldflags="-w -s" hello.go
FROM scratch
COPY --from=builder /go/src/app/hello /
CMD ["/hello"]
[root@es-master1 hello-world]# docker build -t hello .
[root@es-master1 hello-world]# docker image ls hello
REPOSITORY TAG IMAGE ID CREATED SIZE
hello latest df8b3c8897f9 8 seconds ago 1.65MB
3.3改寫官方的helloword
hello.c
[root@es-master1 ~]# cat hello.c
//#include <unistd.h>
#include <sys/syscall.h>
#ifndef DOCKER_GREETING
#define DOCKER_GREETING "Hello from Docker!"
#endif
const char message[] =
DOCKER_GREETING "\n";
void _start() {
//write(1, message, sizeof(message) - 1);
syscall(SYS_write, 1, message, sizeof(message) - 1);
//_exit(0);
syscall(SYS_exit, 0);
}
編譯
[root@es-master1 ~]# gcc -static -Os -nostartfiles -fno-asynchronous-unwind-tables -o './hello' 'hello.c'
[root@es-master1 ~]# strip -R .comment -s 'hello'
[root@es-master1 ~]# ./hello
Hello from Docker!
dockerfile
FROM scratch
COPY hello /
CMD ["/hello"]
[root@es-master1 ~]# docker build -t hello .
#才1.06kB
[root@es-master1 ~]# docker image ls hello
REPOSITORY TAG IMAGE ID CREATED SIZE
hello latest 3b204a40c8cb 14 seconds ago 1.06kB
[root@es-master1 ~]# docker run --rm hello
Hello from Docker!
四、補充
- gcc -D可以定義宏,起到替換、條件編譯的功能;即hello.c中定義了一個宏,我可以在gcc編譯時使用-D替換該宏。就好像我docker鏡像定義了一些變量,但是docker run仍可以-e傳遞變量,覆蓋原有的變量
- gcc -static指定強制使用靜態庫,
- -O 對程序進行優化編譯、鏈接。采用這個選項,整個源代碼會在編譯、鏈接過程中進行優化處理,這樣產生的可執行文件的執行效率可以提高,但是編譯、鏈接的速度就相應地要慢一些,而且對執行文件的調試會產生一定的影響,造成一些執行效果與對應源文件代碼不一致等一些令人“困惑”的情況。因此,一般在編譯輸出軟件發行版時使用此選項。
- -Os 使用了所有-O2的優化選項,但又不縮減代碼尺寸的方法 https://www.cnblogs.com/luolizhi/p/5737091.html
- -nostartfiles 連接的使用不使用標准系統庫。只有你指定的庫才能夠傳遞給連接器。不鏈接系統標准啟動文件,而標准庫文件仍然正常使用
- -fno-asynchronous-unwind-tables 用來不生成CFI指令
- -o 輸出文件名
- stribe 給文件脫褲子。具體就是從特定文件中剝掉一些符號信息和調試信息。 在strip之后, 文件變小了, 仍然可以執行, 這就就節省了很多空間。