`
January 18, 2018 本文阅读量

docker探索

docker 学习实战笔记。

docker 学习实战笔记。关于docker的详细信息参见官方文档

实战环境配置:

系统 Docker
MacOS 17.12.0-ce

实战一 简单部署可执行文件

本次实战是部署一个golang的web服务, 需要mongo, redis支持

  1. 省略代码,打包过程(Mac用户别忘了打包GOOS=linux,0·0)

  2. 编写Dockerfile

FROM alpine # 简版linux

RUN mkdir /app # 在镜像中创建一个文件夹

COPY ./webapp /app 
COPY ./config /app/config
COPY ./logs /app/logs

EXPOSE 35764 # 暴露35764端口,也就是为了从外部可以访问到容器类的服务

WORKDIR /app # 切换到应用文件夹(在镜像执行的时候,会自动切换)
  1. 构建镜像 执行命令 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
  1. 调试容器

执行命令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 #
  1. 总结

本次实战遇到的问题有:

  • 如何让容器内的应用可以访问宿主机的应用,譬如(mongo,redis)?

A: 经过查阅官方文档和google检索。docker会创建一个网桥来负责容器之间,容器与宿主机的通信,如下图: 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服务的时候,一定会接触到的就是:

  • 如何从容器外访问容器内的服务?
  • 如何从容器内访问宿主机的服务?
  • 如何容器间通信?

1.如何从容器外访问容器内的服务?

2.如何从容器内访问宿主机的服务?

3.如何容器间通信?