Getting Start
Docker的作用
- 操作系统虚拟化
- 充分利用服务器资源
- 构建云计算PAAS服务
Docker的优点
- 隔离性,推荐一个Docker容器运行一个服务
- 系统资源隔离,软件依赖隔离,系统环境隔离
- 复用性
- 发布的不只是软件,而是软件和软件的运行环境,包括软件和依赖的安装和配置
- 镜像方便分享复用
- 保持开发与运维环境一致性
- 无需关心分布式服务的端口
- Docker Networking
- 还是需要关心host
- 轻量,启动快速,资源消耗小
- 简单,上手快
安装Docker
- 官网
- ce版本
- 通过安装docker特定的yum源安装
启动/停止
- service docker start/stop/status/info
- 启动docker守护进程
非root用户省去sudo执行docker
- cat /etc/group : 查看docker用户组,如果没有则创建
- usermod -aG docker usr : 将用户加入组
- sudo service docker restart : 重启docker engin
- sudo chmod 777 /var/run/docker.sock : 给套接字附权限
docker设置
- docker镜像,容器和容器配置在/var/lib/docker下
- docker容器在/var/lib/docker/containers下
- 设置链接远程Docker Engin
- export DOCKER_HOST=tcp://server-host:2375
- 修改文件/etc/docker/daemon.json的host
- 设置docker registry
- 在/etc/docker/daemon.json文件中添加
Docker容器
docker容器操作
-
docker run --name hello -i -t ubuntu /bin/bash
- 创建并启动一个名字叫hello的交互式的ubuntu容器
- exit退出交互式界面,容器会停止
- -d : 创建并启动一个daemon容器,要求容器程序不会终止
- -h : 指定容器的host名字
- --restart=always : docker会自动重启以外停止的容器
- stop/kill的容器不会自动重启
- --restart=onfailure:5 : 停止代码为非0才会自动重启,5代表最多重启5次
- -p 80: EXPOSE对外公开80端口
- docker会随即从宿主机的32768-61000中选择一个端口来连接到80端口
- -P对外公开所有EXPOSE的端口
- 也可以指定特定端口连接到80端口 -p 8080:80
- -p 127.0.0.1:8080:80指定特定网络接口
- docker port container_name 80 :查看连接到80端口的端口
- --expose : 指定对外部公开EXPOSE指令中的某个端口
- --privileged
- 特权模式启动容器,使得容器具有几乎所有宿主机的能力,包括一些内核特性和设备访问
- 这种模式可以使我们在docker中运行docker
- 具有一定安全风险
- --cidfile=/tmp/cid.txt : 保存容器id到文件
- --volumes-from : 把指定容器的所有卷都加到当前容器
- --rm : 运行完毕删除容器
- -v :设置卷
-
docker ps
- 查看当前正在运行的容器
- -a : 查看所有容器
- -n 10 : 查看最后10个容器
- --no-trunc : 不使用缩略
-
docker create/start/stop/kill/restart/rm container_name
- 创建/启动/停止/立即停止/重启/删除容器
- 启动会沿用创建时的command
- docker rm `docker ps -a -q`: 删除所有容器
- docker kill -s signal container : 这个操作是发送信号而不是杀掉容器
-
docker attach container_name
- 启动后可以根据容器的command重新附着到容器
-
docker exec -d container_name shell_script
- 在容器内部添加一个daemon进程
- -u 给进程设置用户
- docker exec -i -t container_name /bin/bash : 添加一个交互式窗口
-
docker wait container_name : 阻塞直到容器命令执行完成,并返回返回码
-
docker container prune : 删除所有停止到容器
Docker容器查询
- docker logs
- 查看容器日志,默认日志驱动json-file,新的日志驱动在不断增加
- -f : 实时监控日志,但是之前的日志也会全量显示
- --tail 10 : 查看最后10条,--tail 0 -f合用表示不显示旧日志的实时监控
- 如果日志没有标准输出,而是输出到文件则无法获取
- docker top container_name
- 查看daemon容器内部的进程
- docker stats container_1 container_2
- 查看多个容器的统计信息,包括CPU/MEM/IO等的使用率
- docker inspect container_1 container_2
- 查看多个容器的全面详细信息
- --formate进行信息筛检,支持完整go语言模板,强大
- -f "{{range.Mounts}}{{.}}{{end}}" container_name : 查看容器的卷信息
Docker镜像
Dokcer image命令
- docker images
- docker image image-name
- docker pull registry-url/image-name:tag
- 不加tag,自动下载latest
- 不加registry,从默认registry下载
- docker search image-name
- shot describtion 里的内容会被匹配
- docker commit : 通过容器创建镜像
- 通过基础镜像创建容器
- 通过容器创建镜像
- docker commit container-name jude/centos:test
- jude是镜像的用户名,centos是镜像的仓库名,test是镜像的tag
- commit操作只提交容器与基础镜像有差异的部分
- docker login/logout
- docker tag image-id new-image-name:tag
- docker push repository/image:tag
- 会自动创建仓库
- docker rmi image-id
Dockerfile工作原理
- Dockerfile工作流程
- 将构建上下文上传到docker守护进程
- FROM指令从基础镜像构建容器,所以第一条指令必须是FROM
- 在容器中执行一条指令
- 通过docker commit创建新容器的镜像
- 通过新创建的镜像运行另一个容器
- 执行下一条指令,直到结束
- build Dockerfile
- docker build -f xx -t xx workdir
- -t="jude/centos:test" : 指定仓库,镜像名,标签
- -f path/file : 指定Dockfile路径
- workdir用.表示在当前目录工作
- docker build -t jude/image:tag .
- .dockerignore
- 过滤一些文件,使得不被上传到docker守护进程
- 从Git仓库build Dcokerfile
- docker build -f xx -t xx workdir
- Dockerfile构建缓存
- Dockerfile的每一步中间镜像都会被存储起来
- 下一次构建Dockerfile的时候,会直接发生变化的指令开始
- --no-cache不使用缓存,也可以使用时间来打破指令缓存, ENV EDIT_AT 20181003
- docker history imageid 查看所有缓存
Dockerfile指令详解
- FROM/ONBUILD
- 基础镜像
- ONBUILD RUN ... : 当作为别人的基础镜像时会触发的指令,跟随FROM后运行
- 触发器可以有多个,不会被继承
- RUN
- 构建镜像时需要运行的指令
- ARG
- 为docker build指定参数,支持默认值ARG name=jude
- docker build --build-arg name=7b
- 不要使用ARG传递敏感信息
- 预定义参数
- HTTP_PROXY/HTTPS_PROXY/FTP_PROXY/NO_PROXY
- 也支持全部小写的版本
- CMD/ENTERPOINT
- 容器启动时需要运行的指令
- docker run 会覆盖CMD,但是会作为参数传递给ENTERPOINT(--entrypoint会覆盖ENTERPOINT)
- 同时使用ENTERPOINT和CMD提供可变参数的带默认值的指令
- EXPOSE
- 用来指定端口,使容器内的应用可以通过端口和外界交互。声明了容器应该打开的端口并没有实际上将它打开
- EXPOSE 8080 : 然后再启动容器时使用-P,这样docker会随机从宿主机的32768-61000中选择一个端口来连接到8080端口
- EXPOSE要写在最后?
- WORKDIR
- 指定容器的工作目录,CMD/ENTERPOINT在此目录执行
- docker run -w覆盖WORKDIR
- ENV
- ENV env_a 1或者ENV a=1 b=2来指定一个或多个环境变量
- docker run -e a=b来传递环境变量
- RUN命令中通过$env_a来使用,环境变量也会被保存到容器中
- ADD/COPY
- ADD file/url /path/to/file : 将源文件/URL添加到指定目录
- 只支持构建上下文中没有ignore的文件
- 目的目录不存在,会以755的权限自动创建,UID/GID为0
- 如果ADD一个zip文件,会自动解压缩,解压以添加内容,不覆盖原文件的方式进行
- ADD会使缓存无效
- COPY在守护进程内部执行,而且不会解压缩
- VOLUME
- VOLUME ["/home", "/opt"] : 指定一个或多个卷
- 卷的内容可以被容器访问,但是不会被提交到镜像
- 多个容器可以共享卷的内容,比如源码文件等
- docker run -v 添加/覆盖?卷
- 卷可以通过插件支持第三方存储系统,可用于不同宿主机共享卷
- 后面加上:ro/:rw来指定容器内目录的读写权限
- 利用卷备份数据,Redis备份?
- USER user:group
- 以什么身份启动容器
- docker run -u 来覆盖USER
- 需要先创建用户:RUN groupadd -r ratesuser && useradd -r citimkts -g ratesuser
- 其他
- MAINTAINER : 作者信息
- LABLE a=b c=d
- 为镜像添加元数据,比如version,location,type,role
- docker inspect jude/image :查看元数据
- STOPSIGNAL?
容器间通讯
Docker内部联网
- docker0
- 虚拟以太网桥,ip地址可能是172.17.0.1,用于连接容器和宿主机
- 占用B类保留ip的大部分:172.16-172.30
- veth*/eth0
- docker每创建一个容器,就会创建一组互联的网络接口
- 其中一端以veth开头,插在宿主机的docker0网桥上面
- 另一端是eth0,连接容器内部,ip类似172.17.0.2
- 通过以上方式创建了虚拟子网,类似一个局域网
- 虚拟子网下的容器,除了能链接宿主机的所有ip接口,还能连接与宿主机在同一个局域网的其他机子
- 内部联网的缺点
- 所有应用与容器连接的配置需要硬编码
- 重启容器后,容器的ip会改变
- 无法与不同宿主机的容器通讯
- 连接
- docker inspect container_name 查看被连接容器的 Networking的IPAddress, ip类似172.17.0.2
- 在连接的容器中使用这个局域网地址
通过Docker链接--link来通讯
- 优点
- 无需硬编码
- 缺点
- 无法与不同宿主机的容器通讯
- 需要获取env,麻烦
- 原理
- 通过--link获取被联机容器的内部联网的Ip,存储在客户端容器的env里
- 可以通过env获取地址
- 连接
- docker run --name redis-name redis : 被连接的容器正常启动,不需要公开端口
- docker run --link redis-name:redis-service clinet : 连接的容器可以使用redis-service代替redis的ip
通过公开的端口号通讯
- 优点
- 可以跨越不同宿主机
- 如果有服务治理,那么即使同一台宿主机也不需要关心端口号占用
- 部署服务时可以不需要关心host,port
- 缺点
- 没有服务治理,连接服务需要关心host:port,需要硬编码,port还有可能变化
Docker Networking
-
优点
- 可以跨越不同宿主机
- 通过使用固定port,所有服务都有相同的固定port,无论是否在同一台宿主机
- 如果只有一个服务,连host也是固定的,无论在哪台宿主机
- 即使是分布式服务,在部署服务时不需要关心host和port
-
缺点
- 如果是分布式服务,连接服务时还是需要关心host,只不过可以根据规则自定义,来模拟服务发现机制
-
工作原理
- 任何一个容器启动,ip信息都会存在容器的/etc/hosts里,重启容器会更新/etc/hosts
- 通过解析/etc/hosts,同一个Networing下的容器,都可以ping container-name.network-name连接对方
- container-name是唯一的,这个特性制约了分布式的host
- 一个容器可以隶属于多个Networking
-
指令
- docker network create/rm network-name
- docker network connect/disconnect network-name container-name --alias alias_name
- docker run --net network-name --name container-name
- 查询
- docker network inspect network-name
- docker network ls
总结
- 有服务发现 : Eureka/K8s
- 随机端口+随机端口映射
- 通过ServiceId映射到宿主机host:port来通讯
- 不需要管理host和port
- 支持容器间,容器与非容器都通讯
- 支持跨宿主机通讯
- 不会产生端口冲突
- 没有服务发现
- 同宿主机
- docker link
- 可以用link name代替ip
- 不存在端口冲突问题
- docker link
- 跨宿主机
- 端口映射 [本地开发]
- 需要hard code对方宿主机都host:port
- 无法应对宿主机更改,port修改
- 可能存在端口冲突问题
- 支持非容器与容器通讯
- docker network
- 通过--alias通讯
- 需要关心port
- 不支持非容器与容器通讯
- 没有端口冲突
- 不支持load balance
- 端口映射 [本地开发]
- 同宿主机
- 本地开发环境使用docker compose,会自动创建docker network,并且公开端口。生产环境使用服务治理。
本地与服务器相互调用
- Proxy
- ssh -CfNg -L 8888:awx-dev-34.awx.im:9999 ubuntu@awx-dev-34.awx.im
- 在本地起一个8888端口映射到服务器的9999端口
- Debug
- ssh -CfNg -R 9999:localhost:8888 ubuntu@awx-dev-34.awx.im
- 在服务器启动9999端口映射到本地的8888端口
- 9999端口只作用在服务器的localhost上,如果需要作用在所有ip段上,需要在/etc/ssh/sshd_config下添加Gateway_Prots yes,然后重启服务器并重新添加监听通道
- 实现debug需要服务间用暴露端口的方式调用,而不是docker network调用!!!使用env来将service name调用变为host:port调用
- simpleproxy???
- 其他
- 起的端口必须没被占用
- 服务的端口需要可以访问,也就是用docker compose暴露端口
- 查看和kill ssh端口映射:ps -ef | grep ssh
- Debug模式下,kill本地映射进程也会去除服务器的端口映射进程
- -i 设置ssh key的路径
Dcoker Build/Deploy
jenkins/maven/docker在宿主机运行
- 发布image到Regiester
- jenkins build
- Dockerfile
- RUN maven package -> zip
- ADD zip -> image
- docker push image -> Regiester
- Dockerfile
- jenkins deploy
- pull image
- run image
- jenkins build
- 在服务器生成image
- jenkins build
- pom -> zip
- Dockerfile -> zip
- jenkins deploy
- Dockerfile -> image
- run image
- jenkins build
- 发布项目文件到VOLUME
- 使用以上方法准备空的image和容器
- jenkins build
- pom-> zip
- jenkins deploy
- zip -> VOLUME
- docker start
jenkins/maven/docker使用docker运行
- 发布image到Regiester
- jenkins build
- Dockerfile
- RUN maven package -> zip
- ADD zip -> image
- VOLUME /var/lib/docker
- docker push image -> Regiester
- Dockerfile
- jenkins deploy
- pull image : VOLUME使得容image会下载到宿主机,而不是docker内部
- run image : VOLUME使得容器会运行在宿主机,而不是docker内部
- jenkins build
- 在服务器生成image
- 同理使用VOLUME /var/lib/docker
- 发布项目文件到VOLUME [推荐方案]
- 使用以上方法准备空的image或者容器
- jenkins所在容器和项目所在容器使用同一个VOLUME
Docker Compose
常用命令
- docker-compose ps
- docker-compose pull : 拉去最新的镜像
- docker-compose up -d :
- 以daemon方式创建容器
- 同时创建network
- docker-compose down : 销毁容器和network
- docker-compose rm : 删除停止的容器
- docker start: 启动停止的容器
docker-compose.yml
- image / restart: always / ports: - 80:80 / depends_on:
- command: [ 'xx' ]
- container_name : 容器名字,同时也是network里的service id
- volumes: /home/jude
Docker Swarm
- https://www.imooc.com/article/49061
- docker swarm join-token worker/manager : 显示出完整join-token命令