docker 学习实战笔记。关于docker的详细信息参见官方文档
实战环境配置:
系统 | Docker |
---|---|
MacOS | 17.12.0-ce |
实战一 简单部署可执行文件 #
本次实战是部署一个golang的web服务, 需要mongo, redis支持
-
省略代码,打包过程(Mac用户别忘了打包GOOS=linux,0·0)
-
编写Dockerfile
FROM alpine # 简版linux
RUN mkdir /app # 在镜像中创建一个文件夹
COPY ./webapp /app
COPY ./config /app/config
COPY ./logs /app/logs
EXPOSE 35764 # 暴露35764端口,也就是为了从外部可以访问到容器类的服务
WORKDIR /app # 切换到应用文件夹(在镜像执行的时候,会自动切换)
- 构建镜像
执行命令
docker build -t tp-api:v1 .
执行结果如下:
Sending build context to Docker daemon 55.5MB
Step 1/7 : FROM alpine
---> 3fd9065eaf02
Step 2/7 : RUN mkdir /app
---> Using cache
---> 6948fdc89bbd
Step 3/7 : COPY ./webapp /app
---> Using cache
---> 555307961735
Step 4/7 : COPY ./config /app/config
---> ab15feb5a3ab
Step 5/7 : COPY ./logs /app/logs
---> 0055512da60b
Step 6/7 : EXPOSE 35764
---> Running in db0503538961
Removing intermediate container db0503538961
---> 1d214b7aff6d
Step 7/7 : WORKDIR /app
Removing intermediate container 42889dd384a7
---> f0b05bcb428d
Successfully built f0b05bcb428d
Successfully tagged tp-api:v2
- 调试容器
执行命令docker run -it --rm -p 35765:35764 tp-api:v1
,会进入容器交互模式,如下:
-> /app #
-> /app #
-> /app # ls
config logs webapp
-> /app #
此时输入./webapp
就可以在容器内运行该二进制文件了。
-> /app #
-> /app #
-> /app # ls
config logs webapp
-> /app # ./webapp
-> 2018/01/22 07:38:50 loading config from: [ ./config/dev/config.json & ./config/dev/server.json ]
-> 2018/01/22 07:38:50 load dbconfig file done
-> 2018/01/22 07:38:50 load server config file done
-> /app #
- 总结
本次实战遇到的问题有:
- 如何让容器内的应用可以访问宿主机的应用,譬如(mongo,redis)?
A: 经过查阅官方文档和google检索。docker会创建一个网桥来负责容器之间,容器与宿主机的通信,如下图: 更多资料可以参考Docker — 从入门到实践 总的来说,不想通过容器互联的方式来运行程序,那么就需要配置一个host来提供给容器内的应用访问。那么这个host怎么确认呢?
docker inspect --format "{{.NetworkSettings.Gateway}}" c41c11eefc83 # c41c11eefc83 容器ID
会得到172.17.0.1
(根据系统不同会得到不一样的网关地址)
注意: Mac 上到这里仍然没有成功运行程序,因为这样的配置还是无法访问宿主机器上的Mongo和Redis服务。最终正确的Host应该是docker.for.mac.localhost
附上官方文档的说明Docker-for-Mac-Networking
从17.06开始,我们的建议是连接到特殊的仅限于Mac的DNS名称docker.for.mac.localhost,该名称将解析为主机使用的内部IP地址。
实战二 Docker多阶段构建 #
https://yeasy.gitbooks.io/docker_practice/content/image/multistage-builds.html 链接中已经充分阐述了,多阶段构建的使用场景,本实战只是描述我自己在使用过程中的状况及小小思考。
在实战一中,部署的web服务是一个手动打包好的可执行程序文件。之所以这样部署,是因为当时在练习使用docker,不知道如何制作自动打包的镜像(监介0-0)。 再后来便尝试了自动打包,Dockerfile如下:
FROM golang:1.9-alpine
WORKDIR /go/src/myapp
COPY ./vendor ./vendor
COPY ./webapp.go ./
RUN CGO_ENABLED=0 GOOS=linux ARCH=amd64 go build -o webapp webapp.go
EXPOSE 35764
CMD ["./webapp"]
查看下打包的镜像,足足有282MB,相比第一种打包方式,体积变大了很多(尽管已经使用了golang:1.9-alpine镜像,如果不是使用这个的话,还会更大。。。)。
➜ test-platform git:(master) ✗ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tp-api v1.2 9cbe31c46664 7 seconds ago 282MB
当然为了减小镜像体积,有如下方案:
方案一:可以采用编写shell脚本或手动打包,然后再部署服务。 #
弊端:但是在不同的环境上,shell脚本不能保证百分百可靠,而且还需要该环境支持
方案二:多个Dockerfile, 将编译后的程序及其他文件放入用于部署的镜像中 #
弊端:步骤较为繁琐,因为编译后的文件位于镜像中,必须先将其复制出来;其次是至少需要编写三个文件,一个用于编译的dockerfile.build, 一个用于部署的dockerfile.deploy,一个用于链接两个步骤的shell脚本
方案三: docker多阶段构建 #
为解决以上问题,Docker v17.05 开始支持多阶段构建 (multistage builds)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 Dockerfile
相比于方案二,这是一种更优雅的解决方案。因为在一个dockerfile中你可以给各个阶段命名,然后复制的时候带上--from=stage_name
便可以方便的复制编译后的文件了。
#####
# 编译阶段
####
FROM golang:1.9-alpine AS build
WORKDIR /go/src/test-platform
COPY ./vendor ./vendor
COPY ./webapp.go ./
RUN CGO_ENABLED=0 GOOS=linux go build ./webapp.go
#####
# 部署阶段
#####
FROM alpine
RUN mkdir /app
COPY --from=build /go/src/test-platform/webapp /app
COPY ./config /app/config
COPY ./logs /app/logs
EXPOSE 35764
WORKDIR /app
CMD ["./webapp", "-env $RUN_ENV"]
实战三 Docker网络基础及容器互联 #
使用docker部署web服务的时候,一定会接触到的就是:
- 如何从容器外访问容器内的服务?
- 如何从容器内访问宿主机的服务?
- 如何容器间通信?