0、前言
什么是 Docker
镜像 ?
Docker
就像往集装箱里装货物的码头工人那样,它把应用打包成具有某种标准规格的集装箱,用计算机领域的语言来说,这种按照一定规格封装的集装箱叫 「镜像」 。
Docker
镜像又有什么优势呢 ?
统一的管理服务、持续交付、弹性计算 等等…
如何创建一个镜像呢 ?
下文会带你一起了解如何创建一个 Docker
镜像
1、准备工作
2、步骤
为了避免机器的权限问题,本次演示的所有操作都在 root
下进行
2.1、创建glibc镜像
目的: 修改时区信息的修改
创建Dockerfile的文件夹 alpine_glibc_2.23
,我暂且先起这个名字,为什么这么起后面我会介绍。
为了避免网络问题,我先把几个必要的 apk
包直接放到本地。
1 2 3 4 5 [root@freeipa101 alpine_glibc_2.23] # ll total 11768-rw-r--r-- 1 root root 2943700 Oct 4 15:58 glibc-2 .23-r3 .apk -rw-r--r-- 1 root root 1751110 Oct 4 15:58 glibc-bin-2 .23-r3 .apk -rw-r--r-- 1 root root 7326212 Oct 4 15:58 glibc-i18n-2 .23-r3 .apk
然后创建一个 Dockerfile
文件
1 2 3 4 5 6 FROM alpine:latest MAINTAINER shengguocun<hzshengguocun@corp.netease.com> ENV LANG=C.UTF-8 RUN apk update && apk add tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone COPY glibc-*.apk /tmp/ RUN apk upgrade --update && apk add --allow-untrusted /tmp/ *.apk && rm -f /tmp/ *.apk /var/cache/apk/ *
保存退出,进行 build
操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 [root@freeipa101 alpine_glibc_2.23] Sending build context to Docker daemon 12.03MB Step 1/6 : FROM alpine:latest --- > 196d12cf6ab1 Step 2/6 : MAINTAINER shengguocun<hzshengguocun@corp.netease.com> --- > Using cache --- > 87a5241dd00b Step 3/6 : ENV LANG=C.UTF-8 --- > Using cache --- > 5529e89cde7e Step 4/6 : RUN apk update && apk add tzdata && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone --- > Running in 069c8e8cd 948 fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz v3.8.1-22-g24d67bab3a [http://dl-cdn.alpinelinux.org/alpine/v3.8/main ] v3.8.1-16-g96e1e57fed [http://dl-cdn.alpinelinux.org/alpine/v3.8/community ] OK: 9539 distinct packages available (1/1) Installing tzdata (2018d-r1) Executing busybox-1.28.4-r1.trigger OK: 8 MiB in 14 packages Removing intermediate container 069c8e8cd 948 --- > 1af55928a1c5 Step 5/6 : COPY glibc-*.apk /tmp/ --- > 490259033ddd Step 6/6 : RUN apk upgrade --update && apk add --allow-untrusted /tmp/ *.apk && rm -f /tmp/ *.apk /var/cache/apk/ * --- > Running in b8b7ef2ec402 OK: 8 MiB in 14 packages (1/4) Installing glibc (2.23-r3) (2/4) Installing libgcc (6.4.0-r9) (3/4) Installing glibc-bin (2.23-r3) (4/4) Installing glibc-i18n (2.23-r3) Executing glibc-bin-2.23-r3.trigger OK: 24 MiB in 18 packages Removing intermediate container b8b7ef2ec402 --- > 216a3982623d Successfully built 216a3982623d
现在查看一下刚刚 build
出来的镜像
1 2 3 4 5 [root@freeipa101 alpine_glibc_2.23 ]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 216 a3982623d 10 seconds ago 34.7 MB nginx latest be1f31be9a87 37 hours ago 109 MB alpine latest 196 d12cf6ab1 3 weeks ago 4.41 MB
<none>
就是刚刚打出的镜像,这时候我们需要给他进行重命名,通过 docker tag --help
查看相关的使用
1 2 3 4 5 [root@freeipa101 alpine_glibc_2.23 ] Usage: docker tag SOURCE_IMAGE [:TAG ] TARGET_IMAGE[:TAG ] Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
1 [root@freeipa101 alpine_glibc_2.23 ]# docker tag 216a3982623d docker.io/ricksheng/apline_glibc:2.23
最后一步,跟 GitHub
提交代码一样将镜像推到 Docker hub
上
1 2 3 4 5 6 7 8 [root@freeipa101 alpine_glibc_2.23] # docker push docker .io /ricksheng /apline_glibc :2.23 The push refers to repository [docker.io/ricksheng/apline_glibc] cad05933e86e : Pushing [========================> ] 7 .813MB /15 .67MB a531be207876 : Pushing [========================================> ] 9 .842MB /12 .02MB cad05933e86e : Pushing [==========================================> ] 13 .31MB /15 .67MB cad05933e86e : Pushed 2 .23 : digest : sha256 :1823a0b6171a4182416322e0360ef75230cb0491a3d70ab8cc370535c0c035d8 size : 1161
到这里为止,一个简单的镜像就创建完毕了。
2.2、创建gcc镜像 和上面类似,创建一个 alpine_gcc
文件夹,然后创建一个 Dockerfile
文件
1 [root@freeipa101 alpine_gcc]# vim Dockerfile
1 2 3 FROM docker.io/ricksheng/ apline_glibc: 2.23 MAINTAINER shengguocun<hzshengguocun@corp .netease.com> RUN apk --no-cahe add make g++ libevent openssl-dev libevent-dev linux-headers && rm -rf /var/ cache/apk/ *
进行 build
操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 [root@freeipa101 alpine_gcc]# docker build . Sending build context to Docker daemon 2. 048kB Step 1 /3 : FROM docker.io/ricksheng/apline_glibc:2.23 ---> 216a3982623d Step 2 /3 : MAINTAINER shengguocun<hzshengguocun@corp.netease.com> ---> Running in 88133daefd42 Removing intermediate container 88133daefd42 ---> 622169df1d2d Step 3 /3 : RUN apk --no-cahe add make g++ libevent openssl-dev libevent-dev linux-headers && rm -rf /var/cache/apk/* ---> Running in a0cade3d8d68 apk: unrecognized option : no-cahefetch http://dl -cdn.alpinelinux.org/alpine/v3.8 /main/x86_64/APKINDEX.tar.gz fetch http://dl -cdn.alpinelinux.org/alpine/v3.8 /community/x86_64/APKINDEX.tar.gz (1 /31 ) Installing libstdc++ (6.4 .0 -r9 ) (2 /31 ) Installing binutils (2.30 -r5 ) (3 /31 ) Installing gmp (6.1 .2 -r1 ) (4 /31 ) Installing isl (0.18 -r0 ) (5 /31 ) Installing libgomp (6.4 .0 -r9 ) (6 /31 ) Installing libatomic (6.4 .0 -r9 ) (7 /31 ) Installing pkgconf (1.5 .3 -r0 ) (8 /31 ) Installing mpfr3 (3.1 .5 -r1 ) (9 /31 ) Installing mpc1 (1.0 .3 -r1 ) (10 /31 ) Installing gcc (6.4 .0 -r9 ) (11 /31 ) Installing musl-dev (1.1 .19 -r10 ) (12 /31 ) Installing libc-dev (0.7 .1 -r0 ) (13 /31 ) Installing g++ (6.4 .0 -r9 ) (14 /31 ) Installing libevent (2.1 .8 -r5 ) (15 /31 ) Installing libbz2 (1.0 .6 -r6 ) (16 /31 ) Installing expat (2.2 .5 -r0 ) (17 /31 ) Installing libffi (3.2 .1 -r4 ) (18 /31 ) Installing gdbm (1.13 -r1 ) (19 /31 ) Installing ncurses-terminfo-base (6. 1_p20180818 -r1 ) (20 /31 ) Installing ncurses-terminfo (6. 1_p20180818 -r1 ) (21 /31 ) Installing ncurses-libs (6. 1_p20180818 -r1 ) (22 /31 ) Installing readline (7.0 .003 -r0 ) (23 /31 ) Installing sqlite-libs (3.24 .0 -r0 ) (24 /31 ) Installing python2 (2.7 .15 -r1 ) (25 /31 ) Installing libevent-dev (2.1 .8 -r5 ) (26 /31 ) Installing linux-headers (4.4 .6 -r2 ) (27 /31 ) Installing make (4.2 .1 -r2 ) (28 /31 ) Installing zlib-dev (1.2 .11 -r1 ) (29 /31 ) Installing libcrypto1.0 (1.0 .2p -r0 ) (30 /31 ) Installing libssl1.0 (1.0 .2p -r0 ) (31 /31 ) Installing openssl-dev (1.0 .2p -r0 ) Executing busybox-1.28 .4 -r1 .trigger Executing glibc-bin-2.23 -r3 .trigger OK: 255 MiB in 49 packagesRemoving intermediate container a0cade3d8d68 ---> d7a938e82e4e Successfully built d7a938e82e4e
查看生成的镜像
1 2 3 4 5 6 [root@freeipa101 alpine_gcc]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> d7a938e82e4e 30 seconds ago 248 MB ricksheng/apline_glibc 2.23 216 a3982623d 9 minutes ago 34.7 MB nginx latest be1f31be9a87 37 hours ago 109 MB alpine latest 196 d12cf6ab1 3 weeks ago 4.41 MB
1 [root@freeipa101 alpine_gcc]# docker tag d7a938e82e4e docker.io/ricksheng/alpine_gcc:6.4.0
1 2 3 4 5 6 7 8 9 [root@freeipa101 alpine_gcc]# docker push docker.io/ricksheng/alpine_gcc:6.4 .0 The push refers to repository [docker.io/ricksheng/alpine_gcc] c 8 cb354e6402 : Pushing [======> ] 25.93 MB/213.2 MBc 8 cb354e6402 : Pushing [==========> ] 44.56 MB/2 c 8 cb354e6402 : Pushing 47.85 MB/213 .c 8 cb354e6402 : Pushing [===============> ] 67.65 MB/213.2 MBc 8 cb354e6402 : Pushing [=============================> ] 126.9 MB/213.2 MBc 8 cb354e6402 : Pusheddf64 d3292 fd6 : Mounted from ricksheng/apline_glibc 6.4 .0 : digest: sha256 :7 da0e8489 ff7 d1e0041 b3 edfa57 f1 fb8039 fb9 cd98 d01600471 a2 f29 f9 fdd0 c 6 size: 1373
到这里为止,创建 OpenResty
镜像的准备工作都OK了,下面开始吧。
2.3、创建openresty镜像 老规矩,创建 alpine_openresty/1.11.2.1
目录,同时创建 Dockerfile
文件以及一个 nginx.conf
文件
1 2 3 4 5 [root@freeipa101 1.11.2.1] # ll total 3852-rw-r--r-- 1 root root 570 Oct 4 16:31 Dockerfile -rw-r--r-- 1 root root 1114 Oct 4 16:23 nginx .conf -rw-r--r-- 1 root root 3930804 Oct 4 16:21 openresty-1 .11 .2 .1 .tar .gz
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 worker_processes 1; error_log logs/error.log; events { worker_connections 1024; } http { server { listen 80; location / { default_type text/html; content_by_lua_block { ngx.say("HelloWorld" ) } } } }
1 2 3 4 5 6 7 8 9 FROM docker.io/ricksheng/alpine_gcc:6.4 .0 MAINTAINER shengguocun<hzshengguocun@corp.netease.com>RUN apk add --update perl openssl openssl-dev pcre-dev make gcc musl-dev EXPOSE 80 443 ENV VERSION=1.11.2.1 ADD openresty-$VERSION .tar.gz /usr/local /src RUN cd /usr/local /src/openresty-$VERSION && ./configure --prefix=/usr/local --with-http_v2_module --with-http_ssl_module && make -j4 && make install && rm -rf /usr/local /src/openresty-$VERSION && rm -f /var/cache/apk/* ADD nginx.conf /usr/local /nginx/conf ENTRYPOINT ["/usr/local/nginx/sbin/nginx" , "-g" , "daemon off;" ]
进行 Build
操作( make的输出太长就不贴出来了 ), 完成后查看一下
1 2 3 4 5 6 7 [root@freeipa101 1.11 .2 .1 ]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 65 b5f5a29c4d 27 seconds ago 336 MB ricksheng/alpine_gcc 6.4 .0 d7a938e82e4e 20 minutes ago 248 MB ricksheng/apline_glibc 2.23 216 a3982623d 29 minutes ago 34.7 MB nginx latest be1f31be9a87 37 hours ago 109 MB alpine latest 196 d12cf6ab1 3 weeks ago 4.41 MB
1 [root@freeipa101 1.11 .2 .1 ]# docker tag 65b5f5a29c4d docker.io/ricksheng/openresty:1.11 .2 .1
1 [root@freeipa101 1.11 .2 .1 ]# docker push docker.io/ricksheng/openresty:1.11 .2 .1
到这里为止,我们的镜像就已经打完了,那如何验证呢?
2.4、验证 & 调试 首先你需要做一下身份认证, docker login
1 2 3 4 5 [root@freeipa101 ~]# docker login Login with your Docker ID to push and pull images from Docker Hub. If you don Username (shengguocun@gmail.com): ricksheng Password: Login Succeeded
登录完成之后,你的用户名、密码会以一个 base64
的字符串记录在本地,然后我们需要将镜像拉到本地
1 2 3 4 [root@freeipa101 ~]# docker pull ricksheng/openresty:1.11 .2.1 1.11 .2.1 : Pulling from ricksheng/openrestyDigest: sha256 :12067 a9651f3148f2f916c19681c1bd95783b172e65adc36dcb303903fede11b Status: Image is up to date for ricksheng/openresty:1.11 .2.1
运行这个镜像
1 2 [root@freeipa101 ~]# docker run -d -p 8887 :80 --name demo001 ricksheng/openresty:1.11 .2.1 6 b798 d8 b9 cbf8393151766 ab46 bfad37342 aaf793402841e36 befc99 c 4 a5 c 2 c 9
最后验证一下,请求宿主机的 IP + 端口
1 2 [root@freeipa101 ~] # curl 127.0 .0 .1 :8887 HelloWorld
到这一个完整的创建 OpenResty
的 Docker
镜像的流程就结束了,当然在实际创建镜像的过程中会遇到各种各样的问题,我们需要进入到容器中进行调试。当然新手要注意的一件事 “容器就是容器,不要把容器当虚拟机” 。