深入理解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 源码分析

docker镜像制作

  • 查看docker进程状态
systemctl status docker #查看docker的服务状态
systemctl start docker  #启动 docker 服务
  • 获取base镜像(以centos为例)
docker search centos
docker pull centos
docker images         # 查看镜像
  • 通过镜像创建容器
docker run -tid --name=<容器名>  /bin/bash  # 创建容器并运行
docker ps -a                                         # 查看所有容器的基本信息
docker inspect                         # 查看容器详情
docker exec -it <容器名> /bin/bash                    # 进入容器
exit       #退出容器
  • 容器创建
# 将容器打包制作成镜像
docker commit -m '镜像描述' -a '制作者' <容器名> <制作后的镜像名>  #制作镜像
# 将制作好的镜像打成 tar 包
docker save -o  <镜像名>
# tar包的使用
docker load < tar包所在路径  #
docker images               # 查看加载的镜像

docker容器的生命周期

  • 创建一个容器的主要步骤
1. docker pull xxx  #拉取镜像
2. docker create    #创建一个容器(未启动)
3. 为容器分配文件系统
4. 为容器创建网络
5. 启动容器

容器间基于 --link 的单向通信

# 1、启动一个数据库容器
docker run -dti --name  redis
# 2、启动一个web服务
docker run --name  --link mydb -dti centos
# 3、进入web容器
docker exec -ti  /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:主要起隔离作用
    1. pid namespace:进程隔离
    2. net namespace:网络管理
    3. ipc namespace:IPC(进程间通信)资源管理
    4. mnt namespace:文件系统挂载管理
    5. 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  /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后重启

你可能感兴趣的:(深入理解docker原理)