深入理解docker原理
docker
Docker通过一个包括应用程序运行时所需的一切的可执行镜像启动容器,包括代码、运行时库文件、环境变量和配置文件等。
1.文件系统隔离:每个容器都有自己得root文件系统。
2.进程隔离:每个容器都运行在自己独立的进程环境中。
3.容器间的虚拟网络接口和IP地址都是分开的。
4.资源隔离和分组:使用cgroup将CPU和内存之类的资源独立分配给每个Docker容器。
5.写时复制:文件系统都是通过写时复制创建的,这就意味着文件系统是分层的、快速的,并且占用磁盘空间小。
6.日志:容器产生的STDOUT、STDIN和STDERR这些IO流都会被收集并记入日志,用来进行日志分析和故障排除。
7.交互式shell:用户可以创建一个伪tty终端、将其连接到STDIN,为容器提供一个交互式shell。
8.灵活性:大多数应用程序均能被装箱。
9.轻量级:容器利用并共享主机内核。
10.可交互:可以即时的更新和升级。
11.可移植:一处构建,到处运行。
12.可扩展性:可以增加和分发容器副本。
docker镜像制作
- 查看docker进程状态
systemctl status docker #查看docker的服务状态
systemctl start docker #启动 docker 服务
- 获取base镜像(以centos为例)
docker search centos
docker pull centos
docker images # 查看镜像
- 通过镜像创建容器
docker run -tid --name=<容器名> <image_id> /bin/bash # 创建容器并运行
docker ps -a # 查看所有容器的基本信息
docker inspect <container_id> # 查看容器详情
docker exec -it <容器名> /bin/bash # 进入容器
exit #退出容器
- 容器创建
# 将容器打包制作成镜像
docker commit -m '镜像描述' -a '制作者' <容器名> <制作后的镜像名> #制作镜像
# 将制作好的镜像打成 tar 包
docker save -o <tar包的名字> <镜像名>
# tar包的使用
docker load < tar包所在路径 #
docker images # 查看加载的镜像
docker容器的生命周期
- 创建一个容器的主要步骤
1. docker pull xxx #拉取镜像
2. docker create #创建一个容器(未启动)
3. 为容器分配文件系统
4. 为容器创建网络
5. 启动容器
容器间基于 --link 的单向通信
# 1、启动一个数据库容器
docker run -dti --name <mydb> redis
# 2、启动一个web服务
docker run --name <myweb> --link mydb -dti centos
# 3、进入web容器
docker exec -ti <contain_id> /bin/bash
# 4、在容器ping
ping mydb
容器间利用 brige 网桥实现双向通信
# 1、查看当前网桥
docker network ls
# 2、创建一个新的my-bridge网桥
docker network create -d bridge my-bridge
# 3、将远行的容器加入到网桥my-bridge
docker network connect my-bridge app1
docker network connect my-bridge app2
docker network connect my-bridge app3
# 4、在app1容器中,可以ping app2
ping app2
Volume数据共享
docker run 时用 -v 宿主机目录:容器中的目录
docker run -it -v /宿主机绝对路径目录:/容器内目录:ro 镜像名 【带权限】
创建webpage的容器卷 (/usr/local/tomcat/webapps)
docker create --name webpage -v 宿主机目录:容器中的目录 tomcat /bin/true
docker run -dti -p 8001:8080 --volumes-from webpage --name tomcat1 tomcat /bin/bash
docker run -dti -p 8002:8080 --volumes-from webpage --name tomcat2 tomcat /bin/bash
docker run -dti -p 8003:8080 --volumes-from webpage --name tomcat3 tomcat /bin/bash
docker_compose安装
Docker Login命令用于登陆Docker Registry
登陆成功Docker会将token存储在~/.docker/config.json文件中,从而作为拉取私有镜像的凭证。
# docker login [option] [server]
option列表如下:
--password, -p:密码
--password-stdin:从标准输入中读取密码
--username, -u:用户名
eg:
docker login --username=cheergoivan registry.cn-hangzhou.aliyuncs.com
docker实现原理
- Namespaces:主要起隔离作用
- pid namespace:进程隔离
- net namespace:网络管理
- ipc namespace:IPC(进程间通信)资源管理
- mnt namespace:文件系统挂载管理
- uts namespace:内核和版本标识符隔离。
- Control groups:控制组(限制容器对物理资源的使用,eg:cpu、内存)
- UnionFS:联合文件系统(为容器提供块功能,也就是文件系统)
- Container format:容器格式
Dockerfile 文件怎么写
FROM tomcat:latest # 利用FROM命令设置基准镜像
WORKDIR /usr/local/workdir # cd /usr/local/workdir
ADD test.tar.gz / # 添加文件到根目录并自动解压
ADD docker_web ./ # ADD用于复制本地文件到镜像中, ADD除了复制,还具备添加远程文件功能
EXPOST 8080 # docker run -p 8000:8080 tomcat
ENV JAVA_HOME /usr/local/openjdk8
RUN $(JAVA_HOME)/bin/java-jar xxx.jar # 在docker build 构建时执行的命令
ENTRYPOINT ["ps"] # docker run 容器启动时执行的命令
CMD ["-ef"] # docker run 容器运行后执行的默认的命令或参数
docker源码解析
- docker源码目录下有docker-engine、docker-ce、cli等子项目。
- docker-ce的components下也有cli,engine和packaging。
- 发现docker-ce下的cli和engine与docker家目录下得docker-engine和cli是一样得。也就是docker-ce只是组合了docker-engine,cli等。
1. 如何生成命令行供我们使用?
2. 在调用命令行后,如何访问到docker server 提供的 restful api?
3. docker engine 一定在监听 restful api 对应的地址!
4. docker engine 收到指令,接下来如何执行
- 命令行模块的入口:docker-ce/components/cli/cmd/docker/docker.go
- 每个具体的命令实现:docker-ce/components/cli/cli/command (如:image镜像相关,container容器相关)
- 排查容器启动流程,当然去container目录下,可以看到容器相关命令对应的文件start.go
package main
import (
"github.com/spf13/cobra" //命令行功能依赖的三方库
)
func runStart(dockerCli command.Cli, opts *startOptions) error {
//TODO:利用cobra包解析后,命令行访问docker server提供的restful api
return dockerCli.Client().ContainerStart(ctx, container, startOptions)
}
func NewStartCommand(dockerCli command.Cli) *cobra.Command {
//TODO:
return runStart(dockerCli, &opts)
}
- dockerCli指向 docker/engine/client/container_start.go:ContainerStart方法, 访问restful api的封装方法。
func (cli *Client) ContainerStart(ctx context.Context, containerID string, options types.ContainerStartOptions) error {
//TODO:ContainerStart 方法调用的是 cli.post
}
- 服务端找到监听这个地址的方法是如何处理的。
- docker server的入口函数在 engine目录下: docker.go
- 再看路由的定义 components/engine/api/server/router/container/container.go
func (r *containerRouter) initRouter() {
r.routes = []router.Route{
router.NewPostRoute("/containers/create", r.postContainersCreate),
}
}
- 分析postContainersCreate方法中的关键方法是:s.backend.ContainerCreate()
- engine/api/server/router/container/backend.go 中可以找到 ContainerStart的接口定义
- ContainerStart真正的定义在components/engine/daemon/start.go中可以看到daemon.containerStart()
docker 应用
mysql安装部署
docker pull mysql
docker run -di --name mysqlServer -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
docker exec -it <CONTAINER ID> /bin/bash # 进入mysql
mysql -u root -p123456 # 登陆
nginx部署
docker pull nginx
docker run -di --name=nginxServer -p 80:80 nginx
redis部署
docker pull redis
docker run -di --name=rediServer -p 6379:6379 redis
redis-cli # 可进入client
postgres部署
docker pull postgres # 拉取Postgresq镜像
# 构建镜像容器
docker run -it --name postgres --restart always -e POSTGRES_PASSWORD='123456' -e ALLOW_IP_RANGE=0.0.0.0/0 -v /home/postgres/data:/var/lib/postgresql -p 5432:5432 -d postgres
docker exec -it postgres bash # 进入postgres容器
su postgres # 切换当前用户,再登录数据库
psql -U postgres -W # 设置pg的密码
基于docker-compose部署ElasticSearch集群(单机多节点)
1、安装前准备(问题:bootstrap checks failed)
grep vm.max_map_count /etc/sysctl.conf # 查看vm.max_map_count命令
vm.max_map_count=262144 # 内核设置需要至少设置为262144用于生产
sysctl -w vm.max_map_count=262144 # 设置实时生效
docker pull openjdk:9 # ElasticSearch是基于java,
docker pull openjdk:11 # 需要支持LTS,jdk9以上才支持
2、部署(在/home/elasticsearch下创建docker-compose.yml)
version: '2.2'
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.4.0
container_name: es01
environment:
- node.name=es01
- discovery.seed_hosts=es02
- cluster.initial_master_nodes=es01,es02
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata01:/usr/share/elasticsearch/data
ports:
- 9200:9200
networks:
- esnet
es02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.4.0
container_name: es02
environment:
- node.name=es02
- discovery.seed_hosts=es01
- cluster.initial_master_nodes=es01,es02
- cluster.name=docker-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata02:/usr/share/elasticsearch/data
networks:
- esnet
volumes:
esdata01:
driver: local
esdata02:
driver: local
networks:
esnet:
3、执行docker-compose up
4、基本功能验证
curl http://127.0.0.1:9200/_cat/health # 检查集群状态
curl http://localhost:9200/_cluster/health # 查看集群健康
curl http://localhost:9200/_nodes?pretty # 查看节点信息
docker logs -f es01 # 查看 es01节点的日志
docker restart es01 && docker restart es02 # 修改config/elasticsearch.yml后重启