入门理解docker的一些概念时,可以把docker和虚拟机进行类比(当然无论从底层还是从应用来说它们都很不一样)
- Docker 可以认为是 vmware或者virtualbox
- 镜像 可以认为是 xxx.iso
- 容器 可以认为是 virtualbox运行xxx.iso后的系统
- 镜像 是容器的基础
一些常用指令
-
$ docker run --name webserver -d -p 80:80 nginx
这条命令会用nginx
镜像启动一个容器,命名为webserver
,并且映射到80 端口,这样我们可以用浏览器去访问这个nginx
服务器。 -
$ docker exec -it webserver bash
使用docker exec
命令进入容器,修改其内容。 -
做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个
docker commit
命令,可以将容器的存储层保存下来成为镜像docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
docker commit的坏处:黑箱操作,docker diff只能提供一些线索,除了制作者本人外其他人都不知道这个镜像的详细情况
-
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
-
dockerfile所在文件夹和镜像容器的关系?
Dockerfile详解
FROM 指定基础镜像
服务类镜像:nginx、redis、mongo、mysql、httpd、php、tomcat 语言应用镜像:node、openjdk、python、ruby、golang 空白镜像:scratch 指定版本时自动安装latest
RUN 执行命令
每一个 RUN 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。 正确的写法应该是这样:
FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
rm
用来清理无关的东西
COPY 复制文件
COPY [--chown=:] <源路径>... <目标路径>
目标路径可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
VOLUME 定义匿名卷
容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库文件应该保存于卷(volume)中,后面的章节我们会进一步介绍 Docker 卷的概念。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在 Dockerfile 中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。
VOLUME /data
这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。当然,运行时可以覆盖这个挂载设置。
EXPOSE 声明端口
- 在容器中使用端口不需要特殊声明
- 若需要这个端口暴露出来,需要在Dockerfile中声明
- 若需要容器的端口指定映射到宿主的端口,需要在启动一个镜像为容器时,用 -p 参数来进行端口映射
构建镜像
-
docker build [选项] <上下文路径/URL/->
$ docker build -t nginx:v3 .
这里的 . ,指的是上下文的目录,docker build命令会将该目录下的内容打包交给Docker引擎以构建镜像,一般来说,应该会将 Dockerfile 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个 .dockerignore -
$ docker build - < context.tar.gz
如果发现标准输入的文件格式是 gzip、bzip2 以及 xz 的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建。
进入容器
当-i -t
参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
$ docker exec -it 69d1 bash
root@69d137adef7a:/#
数据管理
-
数据卷
数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
- 数据卷 可以在容器之间共享和重用
- 对 数据卷 的修改会立马生效
- 对 数据卷 的更新,不会影响镜像
- 数据卷 默认会一直存在,即使容器被删除
Dockerfile最佳实践
-
容器只运行单个应用
若在一个容器中运行多个进程
- 非常长的构建时间(修改前端之后,整个后端也需要重新构建)
- 非常大的镜像大小
- 多个应用的日志难以处理(不能直接使用stdout,否则多个应用的日志会混合到一起)
- 横向扩展时非常浪费资源(不同的应用需要运行的容器数并不相同)
- 僵尸进程问题 - 你需要选择合适的init进程
项目中实际代码阅读
-
需要准备的内容:Dockerfile,start.sh,node.tar安装包,dynamodb_local_latest.tar安装包,这些东西放在docker的上下文中,最后和dockerfile一起打包上传
-
Dockerfile:
-
FROM
官方的java镜像, -
ADD
把node安装包、dynamodb的安装包放在镜像的/data/,start.sh放在镜像的/opt/ -
RUN
修改start.sh的执行权限 -
ENV
配置环境变量-
ENV PATH /data/node/bin:$PATH
PATH)
-
ENV DYNAMO_ENDPOINT http://localhost:8000
定义dynamo的端口
-
-
RUN
安装pm2, dynamodb-admin, redis-server, net-tools, vim -
EXPOSE
暴露端口,顺序分别为dynamo-admin, gx, boss -
ENTRYPOINT
指定入口点,类似于RUN指令,在容器建立好,运行前的准备工作,可以把准备工作写在一个脚本,如start.sh,然后指定为ENTRYPOINT
-
-
start.sh
:- 用nohup的方法运行dynamodb和redis
- 运行gx代码
- 运行boss