2018-09-17 21:02:53 songcf_faith 阅读数 2817
  • 基于Docker的微服务实战 - Spring Cloud为例

    基于Docker的微服务实战视频教程,Docker技术的一致性交付能力和应用隔离使得它成为微服务实践中的重要一环。本次分享讨论微服务架构的特点,基于Docker构建一个微服务应用,并给出一个Spring Cloud应用示例。

    12054 人正在学习 去看看 CSDN讲师

0.前言

首先要知道一个运行的容器,其实就是一个受到隔离和资源限制的Linux进程——对,它就是一个进程。而本文主要来探讨Docker容器实现隔离用到的技术Linux Namespace。

1.关于 Linux Namespace

Linux提供如下Namespace:

Namespace   Constant          Isolates
Cgroup      CLONE_NEWCGROUP   Cgroup root directory
IPC         CLONE_NEWIPC      System V IPC, POSIX message queues
Network     CLONE_NEWNET      Network devices, stacks, ports, etc.
Mount       CLONE_NEWNS       Mount points
PID         CLONE_NEWPID      Process IDs
User        CLONE_NEWUSER     User and group IDs
UTS         CLONE_NEWUTS      Hostname and NIS domain name

以上Namespace分别对进程的 Cgroup root、进程间通信、网络、文件系统挂载点、进程ID、用户和组、主机名域名等进行隔离。

创建容器(进程)主要用到三个系统调用:

  • clone() – 实现线程的系统调用,用来创建一个新的进程,并可以通过上述参数达到隔离
  • unshare() – 使某进程脱离某个namespace
  • setns() – 把某进程加入到某个namespace

2.举个例子(PID namespace)

1) 启动一个容器

$ docker run -it busybox /bin/sh
/ #

2) 查看容器中的进程id(可以看到/bin/sh的pid=1)

/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    5 root      0:00 ps

3) 查看宿主机中的该/bin/sh的进程id

# ps -ef |grep busy
root      3702  3680  0 15:53 pts/0    00:00:00 docker run -it busybox /bin/sh

可以看到,我们在Docker里最开始执行的/bin/sh,就是这个容器内部的第1号进程(PID=1),而在宿主机上看到它的PID=3702。这就意味着,前面执行的/bin/sh,已经被Docker隔离在了一个跟宿主机完全不同的世界当中。

而这就是Docker在启动一个容器(创建一个进程)时使用了PID namespace

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL);

这时候,Docker就会在这个PID=3702的进程启动时给他施一个“障眼法”,让他永远看不到不属于它这个namespace中的进程。这种机制,其实就是对被隔离应用的进程空间做了手脚,使得这些进程只能看到重新计算过的进程编号,比如PID=1。可实际上,他们在宿主机的操作系统里,还是原来的第3702号进程。

然后如果你自己只用PID namespace使用上述的clone()创建一个进程,查看ps或top等命令时,却还是能看到所有进程。说明并没有完全隔离,这是因为,像ps、top这些命令会去读/proc文件系统,而此时你创建的隔离了pid的进程和宿主机使用的是同一个/proc文件系统,所以这些命令显示的东西都是一样的。所以,我们还需要使其它的namespace隔离,如文件系统进行隔离。

3.对照Docker源码

当启动一个docker容器时,会调用到dockerd提供的/containers/{name:.*}/start接口,然后启动一个容器,docker服务收到请求后,调用关系如下:

//注册http handler
router.NewPostRoute("/containers/{name:.*}/start", r.postContainersStart)
//
func (s *containerRouter) postContainersStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error 
//
func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, checkpoint string, checkpointDir string) error 
//
func (daemon *Daemon) containerStart(container *container.Container, checkpoint string, checkpointDir string, resetRestartManager bool) (err error) {
    //...
    spec, err := daemon.createSpec(container)
	//...
    err = daemon.containerd.Create(context.Background(), container.ID, spec, createOptions)
	//...
	pid, err := daemon.containerd.Start(context.Background(), container.ID, checkpointDir,
		container.StreamConfig.Stdin() != nil || container.Config.Tty,
		container.InitializeStdio)
	//...
	container.SetRunning(pid, true)
	//...
}

可以看到在Daemon.containerStart接口中创建并启动了容器,而创建容器时传入的spec参数就包含了namespace,我们再来看看daemon.createSpec(container)接口返回的spec是什么:

func (daemon *Daemon) createSpec(c *container.Container) (retSpec *specs.Spec, err error) {
    s := oci.DefaultSpec()
    //...
    if err := setUser(&s, c); err != nil {
		return nil, fmt.Errorf("linux spec user: %v", err)
	}
	if err := setNamespaces(daemon, &s, c); err != nil {
		return nil, fmt.Errorf("linux spec namespaces: %v", err)
	}
	//...
	return &s
}

//oci.DefaultSpec()会调用DefaultLinuxSpec,可以看到返回的spec中包含了namespace
func DefaultLinuxSpec() specs.Spec {
    s := specs.Spec{
		Version: specs.Version,
		Process: &specs.Process{
			Capabilities: &specs.LinuxCapabilities{
				Bounding:    defaultCapabilities(),
				Permitted:   defaultCapabilities(),
				Inheritable: defaultCapabilities(),
				Effective:   defaultCapabilities(),
			},
		},
		Root: &specs.Root{},
	}
	s.Mounts = []specs.Mount{
		{
			Destination: "/proc",
			Type:        "proc",
			Source:      "proc",
			Options:     []string{"nosuid", "noexec", "nodev"},
		},
		{
			Destination: "/sys/fs/cgroup",
			Type:        "cgroup",
			Source:      "cgroup",
			Options:     []string{"ro", "nosuid", "noexec", "nodev"},
		},
		//...
	}

	s.Linux = &specs.Linux{
	    //...
		Namespaces: []specs.LinuxNamespace{
			{Type: "mount"},
			{Type: "network"},
			{Type: "uts"},
			{Type: "pid"},
			{Type: "ipc"},
		},
		//...
	//...
	return s
}

//而在setNamespaces中还会根据其它配置对namespace进行修改
func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error {
	userNS := false
	// user
	if c.HostConfig.UsernsMode.IsPrivate() {
		uidMap := daemon.idMapping.UIDs()
		if uidMap != nil {
			userNS = true
			ns := specs.LinuxNamespace{Type: "user"}
			setNamespace(s, ns)
			s.Linux.UIDMappings = specMapping(uidMap)
			s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDs())
		}
	}
	// network
	if !c.Config.NetworkDisabled {
		ns := specs.LinuxNamespace{Type: "network"}
		parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2)
		if parts[0] == "container" {
			nc, err := daemon.getNetworkedContainer(c.ID, c.HostConfig.NetworkMode.ConnectedContainer())
			if err != nil {
				return err
			}
			ns.Path = fmt.Sprintf("/proc/%d/ns/net", nc.State.GetPID())
			if userNS {
				// to share a net namespace, they must also share a user namespace
				nsUser := specs.LinuxNamespace{Type: "user"}
				nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", nc.State.GetPID())
				setNamespace(s, nsUser)
			}
		} else if c.HostConfig.NetworkMode.IsHost() {
			ns.Path = c.NetworkSettings.SandboxKey
		}
		setNamespace(s, ns)
	}

	// ipc
	ipcMode := c.HostConfig.IpcMode
	switch {
	case ipcMode.IsContainer():
		ns := specs.LinuxNamespace{Type: "ipc"}
		ic, err := daemon.getIpcContainer(ipcMode.Container())
		if err != nil {
			return err
		}
		ns.Path = fmt.Sprintf("/proc/%d/ns/ipc", ic.State.GetPID())
		setNamespace(s, ns)
		if userNS {
			// to share an IPC namespace, they must also share a user namespace
			nsUser := specs.LinuxNamespace{Type: "user"}
			nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", ic.State.GetPID())
			setNamespace(s, nsUser)
		}
	case ipcMode.IsHost():
		oci.RemoveNamespace(s, specs.LinuxNamespaceType("ipc"))
	case ipcMode.IsEmpty():
		// A container was created by an older version of the daemon.
		// The default behavior used to be what is now called "shareable".
		fallthrough
	case ipcMode.IsPrivate(), ipcMode.IsShareable(), ipcMode.IsNone():
		ns := specs.LinuxNamespace{Type: "ipc"}
		setNamespace(s, ns)
	default:
		return fmt.Errorf("Invalid IPC mode: %v", ipcMode)
	}

	// pid
	if c.HostConfig.PidMode.IsContainer() {
		ns := specs.LinuxNamespace{Type: "pid"}
		pc, err := daemon.getPidContainer(c)
		if err != nil {
			return err
		}
		ns.Path = fmt.Sprintf("/proc/%d/ns/pid", pc.State.GetPID())
		setNamespace(s, ns)
		if userNS {
			// to share a PID namespace, they must also share a user namespace
			nsUser := specs.LinuxNamespace{Type: "user"}
			nsUser.Path = fmt.Sprintf("/proc/%d/ns/user", pc.State.GetPID())
			setNamespace(s, nsUser)
		}
	} else if c.HostConfig.PidMode.IsHost() {
		oci.RemoveNamespace(s, specs.LinuxNamespaceType("pid"))
	} else {
		ns := specs.LinuxNamespace{Type: "pid"}
		setNamespace(s, ns)
	}
	// uts
	if c.HostConfig.UTSMode.IsHost() {
		oci.RemoveNamespace(s, specs.LinuxNamespaceType("uts"))
		s.Hostname = ""
	}

	return nil
}
func setNamespace(s *specs.Spec, ns specs.LinuxNamespace) {
	for i, n := range s.Linux.Namespaces {
		if n.Type == ns.Type {
			s.Linux.Namespaces[i] = ns
			return
		}
	}
	s.Linux.Namespaces = append(s.Linux.Namespaces, ns)
}

其实很早以前Docker创建一个容器,获取namespace是通过CloneFlags函数,后来有了开放容器计划(OCI)规范后,就改为了以上面代码中方式创建容器。OCI之前代码如下:

var namespaceInfo = map[NamespaceType]int{
	NEWNET:  unix.CLONE_NEWNET,
	NEWNS:   unix.CLONE_NEWNS,
	NEWUSER: unix.CLONE_NEWUSER,
	NEWIPC:  unix.CLONE_NEWIPC,
	NEWUTS:  unix.CLONE_NEWUTS,
	NEWPID:  unix.CLONE_NEWPID,
}

// CloneFlags parses the container's Namespaces options to set the correct
// flags on clone, unshare. This function returns flags only for new namespaces.
func (n *Namespaces) CloneFlags() uintptr {
	var flag int
	for _, v := range *n {
		if v.Path != "" {
			continue
		}
		flag |= namespaceInfo[v.Type]
	}
	return uintptr(flag)
}
func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*initProcess, error) {     t := "_LIBCONTAINER_INITTYPE=standard"
    //
    //没错,就是这里~
    //
    cloneFlags := c.config.Namespaces.CloneFlags()
    if cloneFlags&syscall.CLONE_NEWUSER != 0 {
        if err := c.addUidGidMappings(cmd.SysProcAttr); err != nil {
            // user mappings are not supported
            return nil, err
        }
        enableSetgroups(cmd.SysProcAttr)
        // Default to root user when user namespaces are enabled.
        if cmd.SysProcAttr.Credential == nil {
            cmd.SysProcAttr.Credential = &syscall.Credential{}
        }
    }
    cmd.Env = append(cmd.Env, t)
    cmd.SysProcAttr.Cloneflags = cloneFlags
    return &initProcess{
        cmd:        cmd,
        childPipe:  childPipe,
        parentPipe: parentPipe,
        manager:    c.cgroupManager,
        config:     c.newInitConfig(p),
    }, nil
}

现在,容器运行时,通过OCI这个容器运行时规范同底层的Linux操作系统进行交互,即:把容器操作请求翻译成对Linux操作系统的调用(操作Linux Namespace和Cgroups等)。

参考

2020-01-13 00:56:25 sinat_35543900 阅读数 13
  • 基于Docker的微服务实战 - Spring Cloud为例

    基于Docker的微服务实战视频教程,Docker技术的一致性交付能力和应用隔离使得它成为微服务实践中的重要一环。本次分享讨论微服务架构的特点,基于Docker构建一个微服务应用,并给出一个Spring Cloud应用示例。

    12054 人正在学习 去看看 CSDN讲师

目录

docker原理

docker基础概念

docker镜像

构建镜像

Dockerfile

docker四种基础网络


docker原理

docker :容器技术,其原理基于Linux内核的namespace和Cgroup,实现资源的隔离,访问的控制。

docker架构图:

 

namespace(名称空间):其作用为实现访问隔离,将内核的全局资源进行封装,这样每一个namspace都具有独立的资源,因此不同的进程在各自的namespace当中运行不会互相的干扰。linux内核提供了6类namespace实现访问隔离:

  1. UTS(主机和域名)
  2. network(网络
  3. user(用户)
  4. IPC(进程间通信)
  5. PID(进程号)
  6. Mount(文件系统挂载点)

Croup:实现各类资源的控制与分配,其功能由各类的Cgroup子系统实现:

  1. CPU子系统:限制CPU的占比
  2. CPUacct子系统:统计各类Cgroup 对CPU的使用情况
  3. memory子系统:限制所能使用的内存上限
  4. device子系统:控制进程对设备的访问
  5. bilio子系统:限制进程对block I/O的带宽
  6. cpuset子系统:为一组进程指定CPU和内存节点

容器=namesapce+Cgroup+rootfs+docker_engine

docker基础概念

  1. docker镜像:创建容器的基础
  2. docker仓库:镜像的管理与存储
  3. docker容器:基于镜像运行应用服务

 

docker采用的是C/S架构,docker客户端与docker-deamon,docker-deamon 与docker-regsitry之间通信采用的是HTTPS/HTTP。默认条件下docker采用的方式https协议。

docker hub:https://hub.docker.com:官方提供个社区用户的镜像仓库,用户注册账号,可以管理自己制作的镜像,dockerhub主要的功能是提供各类镜像的个社区的用户。当然用户也可以自己搭建自己的镜像仓库,harbor为最受欢迎的开源私有镜像仓库,后面的docker-registry当中会详细介绍。

安装与配置docker:

测试系统为centos7,内核版本为:3.10.0-957.el7.x86_64

yum仓库提供的docker的版本为: 1.13.1,

1,移除centos7 所带的docker以及其组件

yum remove docker*

2,安装不同版本的docke-ce,这里不选择最新版的docker,选择的版本的是:19.03.4

#添加清华大学的docker-ce的yum源,使用yum直接安装
wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo
#清除yum缓存
yum cleanall
#生成仓库信息
yum repolist
#查看提供的docker-ce的版本信息
yum info docker-ce

#显示信息如下:
[root@localhost yum.repos.d]# yum info docker-ce
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * epel: hk.mirrors.thegigabit.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
Available Packages
Name        : docker-ce
Arch        : x86_64
Epoch       : 3
Version     : 19.03.4
Release     : 3.el7
Size        : 24 M
Repo        : docker-ce-stable/x86_64
Summary     : The open-source application container engine
URL         : https://www.docker.com
License     : ASL 2.0
Description : Docker is a product for you to build, ship and run any application as a
            : lightweight container.
            : 
            : Docker containers are both hardware-agnostic and platform-agnostic. This means
            : they can run anywhere, from your laptop to the largest cloud compute instance and
            : everything in between - and they don't require you to use a particular
            : language, framework or packaging system. That makes them great building blocks
            : for deploying and scaling web apps, databases, and backend services without
            : depending on a particular stack or provider.

#通过yum源直接安装docker-ce
yum install docker-ce

 

3,dockerhub服务器器位于美国,访问速度慢,不过国内很多服务商提供了免费的加速,比如,网易,阿里。

配置加速:

配置文件:/etc/docker/daemon.json

{
    "registry-mirrors": ["https://registry.docker-cn.com","http://hub-mirror.c.163.com"]
}

几个常用的docker命令,后面经常会用到这里介绍一下用法:

#从镜像仓库当中拉去镜像
docker pull REGISTRY/IMAGE_NAME:TAG
#上传镜像至镜像仓库
docker push REGISTRY/IMAGE_NAME:TAG
#在dockerhub当中查找镜像
docker search IMAGES
#基于镜像运行为容器
docker run [OPTIONS] REGISTRY/IMAGE_NAME:TAG
    #options:
        -i/--interactive:交互式,及时没有连接都保持STDIN状态,使用时通常与-i参数一起使用
        -t:启动一个为终端,使用时通常与-t参数一起使用
        --name:指定容器的名称
        

 

docker镜像

docke镜像原理:

  1,union filesystem(联合文件系统):是指不同的文件系统统一组织,统一挂载,其外部表现则为一个文件系统,docker image采用了这种方式实现。docker文件系统为overlay2,文件系统分层构建,统一挂载。

2,COW(写时复制),镜像构建完成之后在没有使用时,不会占用系统任何的资源,只有当使用镜像时才会对其分配系统资源。与linux 

fork创建进程相似,通过父进程创建子进程,初始化时系统化不会分配多余的资源给子进程,子进程与父进程公用系统资源,当子进程进行作业时,才会分配器自己的资源。

底层为系统内核,与联合文件系统,往上为各个应用的分层只读构建,最外层为可写,重新构建镜像只需在操作最外层可写层。当然这样的缺点是多次重复的构建会导致镜像的体积变大,运行效率低下。

3,镜像表示方式:

remote_dockerhub.com/namespace/registry/image_name:tag

  • remote_dockerhub.com:是指远程docker仓库的域名,这里也可以是ip:port
  • namespace :用户空间
  • registry:仓库名称
  • image_name:镜像名称
  • tag:镜像的版本

实践:

#从dockerhub当中查询nginx基础镜像
docker search nginx
#部分结果显示
[root@localhost ~]# docker search nginx
NAME                              DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
nginx                             Official build of Nginx.                        12189               [OK]                
jwilder/nginx-proxy               Automated Nginx reverse proxy for docker con??  1687                                    [OK]
richarvey/nginx-php-fpm           Container running Nginx + PHP-FPM capable of??  745                                     [OK]
linuxserver/nginx                 An Nginx container, brought to you by LinuxS??  81                                      
bitnami/nginx                     Bitnami nginx Docker Image                      72                                      [OK]
tiangolo/nginx-rtmp               Docker image with Nginx using the nginx-rtmp??  59                                      [OK]
nginxdemos/hello                  NGINX webserver that serves a simple page co??  31                                      [OK]

构建镜像

构建镜像的方式分为:镜像通过已存在容器构建,通过dockerfile构建镜像

1,通过已有容器构建镜像,

#运行一个容器
docker run --name nginx_web -it -p 8080:80 nginx  
#保存为镜像文件
docker commit -m "nginx_test" -a "zhang" nginx_web learn_test/nginx_test:v0.0.1 
#显示结果:
[root@localhost ~]# docker  images
REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
learn_test/nginx_test    v0.0.1              476f3e86d175        16 seconds ago      126MB
nginx                    latest              540a289bab6c        3 weeks ago         126MB
tomcat                   latest              882487b8be1d        3 weeks ago         507MB
nginx                    latest              5a9061639d0a        4 weeks ago         126MB
httpd                    latest              66a97eeec7b8        4 weeks ago         154MB
busybox                  latest              19485c79a9bb        2 months ago        1.22MB
registry                 latest              f32a97de94e1        8 months ago        25.8MB
lorel/docker-stress-ng   latest              1ae56ccafe55        3 years ago         8.1MB
#使用docker login 登录dockerhub,可以将本镜像推送到docker hub 当中
docker login -u user_name 
#推送:
docker push learn_test/nginx_test:v0.0.1

2,使用Dockerfile制作镜像:Dockerfile可分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令,Dockerfile规定除注释信息之外的第一个指令必须是FROM指定基础进项镜像信息

Dockerfile

  • FROM:指定构建镜像的基础镜像 
FROM <IMAGE>
#FROM nginx
  • LABLE:一般用户指定作者有限
LABEL key="value"
#LABEL miantainer="liu@163.com"
  • ADD:复制指定目录的文件到容器当中的指定目录,文件是tar压缩文件时,会自动解压,同时支持URL,但是URL是tar压缩的文件时,不会解压
ADD <src> <dest>
#ADD /home/test.tar /usr/local/src/
#ADD  https://downloads.mariadb.org/interstitial/mariadb-5.5.66/source/mariadb-5.5.66.tar.gz /home/test/mariadb/

COPY:复制文件到容器的指定目录,与ADD不同的是,不支持tar压缩文件的自动解压

COPY <src> <dest>
#COPY /home/test /usr/local/src/
  • TAG:ARG指令定义了用户可以在编译时或者运行时传递的变量,如使用如下命令:--build-arg <varname>=<value>,也就是Dockfile的环境变量,
ARG <name>[=<default value>]
#ARG nginx_version=1.1.14
  • ENV:.ENV指令是在dockerfile里面设置环境变量,不能在编译时或运行时传递。可以理解为容器的环境变量。
ENV <key>=<value>
#ENV NGINX_WEB_PATH=/data/web/
  • RUN:在容器当中运行指令。
RUN <command> 
RUN ["executable", "param1", "param2"] (exec form)

#run运行有两种格式,一种格式run <command> 采用的是shell运行的方式,默认是/bin/sh -c 运行命令
第二种格式是以docker exec 的方式运行。

RUN yum install vim -y \
    yum install mariadb 
RUN ["yum","install","vim","-y"] 


  • CMD :容器的默认执行体,以entrypiont相似,但是主要的区别在默认上面,当容器没有entrypoint的时候,那么执行的就是CMD,当然docker run 指定的entrypoint时,那么CMD会被指定的entrypoint覆盖。指定的就是指定的让entrypoint
CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;
CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用;
CMD ["param1","param2"] 提供给 ENTRYPOINT 的默认参数;

启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。

  • ENTRYPOINT:容器启动之后真正的执行体
  • ENTRYPOINT ["executable", "param1", "param2"]
    ENTRYPOINT command param1 param2(shell中执行
    
    ENTRYPOINT :每一个dockfile当中只有一条会执行,当存在多条时,只会执行最后一条
    

     

  • EXPOSE:指定容器暴露给系统的端口,但是这个端口信息在容器运行之前和系统之间是不存在端口映射的关系,只有在容器运行时使用-p或-P指定端口才会有端口映射。
EXPOSE <port>
  • VOLUM :指定容器的挂载卷目录
VOLUM <path>
  • WORKDIR:指定指定工作的目录,RUN ,CMD等指令当中可以进行调用
WORKDIR /path/
  • ONBUILD:指定当前Dockfile构建的镜像为基础镜像,ONBUILD在此镜像的基础之上再次经常操作,当用此镜像作为基础镜像构建镜像时,ONBUILD相当在构建镜像的Dockerfile后加入了额外的指令。
ONBUILD <command>

一个实例:

#nginx_test
FORM nginx
LABEL maintainer="zhang <**163.com>"

ARG nginx_test_version=0.0.1

ENV NGINX_WEB_DIR=/data/nginx/web_test/

RUN yum install epel-release && \
     bash nginx.sh && \
        yum install vim -y
EXPOSE 80

CMD ["/bin/sbin/nginx”,"-g","deamon off"]

nginx.sh

#!/bin/bash
echo "www.lili.com 192.168.10.10" >> /etc/hosts
echo > /etc/nginx/conf.d/test.conf< <EOF
server{
    server_name www.lili.com;
    listen 80;
    index test.html 
    root $(NGINX_WEB_DIR)
}
EOF

docker四种基础网络

docker默认的情况下容器与容器之间进行通信是采用bridge,当然除此之外,docker还支持none,host,container,overlay等通通信模型。其原理是基于kernel的network space进行网络空间的隔离,虚拟网络设备实现容器与容器,容器与主机之间的通信。以及跨主机的通行。

  • bridge:桥接,这是容器与容器间通信默认采用的方式,通过虚拟的网桥docker0实现容器与容器之间的通行。网络模型如:下:

容器的IP与主机的IP属于不同网段,容器与主机之间进行通信需要通过防火墙进行路由转发,而主机上容器与容器之间进行通信,则需要通过docker0 这个虚拟网桥。veth*表示虚拟的网络物理接口。

  • host:容器与主机共用主机共享网络设备eth0,主机与容器处于同一网段,这样就没有netwo namespace的网络隔离作用,容器也没有自己的网络协议栈。

none:主机与容器之间,容器与容器之间没有任何的通信,容器的网络完全与外界隔离

container:容器通信使用的是其他容器的network namespace。容器与容器之间不存在网络隔离,当时容器与主机之间却处于不同网段,他们之间的网络又相互隔离。

docker 原生的的网络解决方案还overlay。第三方的网络解决方案如:flannel等

 

 

 

2019-11-04 02:04:55 scj1014 阅读数 16
  • 基于Docker的微服务实战 - Spring Cloud为例

    基于Docker的微服务实战视频教程,Docker技术的一致性交付能力和应用隔离使得它成为微服务实践中的重要一环。本次分享讨论微服务架构的特点,基于Docker构建一个微服务应用,并给出一个Spring Cloud应用示例。

    12054 人正在学习 去看看 CSDN讲师

1. Docker理念

Docker是基于Go语言开发的云开源项目。

Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。

Linux 容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的。将应用运行在 Docker 容器上面,而 Docker 容器在任何操作系统上都是一致的,这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。

总之一句话,解决了运行环境和配置问题软件容器,方便做持续集成并且有助于整体发布的容器虚拟化技术。

2. Docker引擎

图片

Docker Engine 是具有以下主要组件的客户端和服务端应用程序:

  • 服务器时一种长期运行的程序,称为守护程序进程(dockerd 命令)
  • REST API ,它指定程序可以用来与守护进程进行通信并指示其操作的接口
  • 命令行界面(CLI)客户端(docker 命令)

CLI使用Docker REST API 通过脚本或者直接CLI 命令来控制Docker守护程序与Docker守护程序进行交互。

3. Docker架构

Docker使用C-S 架构。Docker客户端与守护进程进行通信,该守护进程完成了构建,运行和分发Docker容器的任务。Docker客户端和守护程序可以在同一操作系统上运行,也可以将Docker客户端连接到远程Docker守护程序。

图片

3.1. Docker守护程序

Docker守护程序侦听Docker API请求并管理Docker对象,例如镜像,容器,数据卷等。守护程序还可以与其他守护程序通信以管理Docker服务。

3.2. Docker客户端

Docker客户端是许多Docker用户与Docker交互的主要方式。同时,Docker客户端可以与多个守护程序通信。

3.3. Docker仓库

Docker仓库存储着Docker镜像。其中,Docker Hub 是任何人都可以使用的Docker仓库,并且默认情况下,当你在使用docker pull 的命令时,会从Docker Hub上下载你所需要的镜像,但是,我们也可以自己搭建私人的Docker镜像仓库。

3.4. Docker镜像

Docker镜像是用来创建Docker容器的。通常,一个镜像基于另一个镜像,并进行了一下其他自定义操作。

除了在使用镜像仓库里的镜像外,我们也可以构建自己的镜像,例如我们可以使用docker build命令来构建自己的镜像,也可以使用简单的语法创建一个DockerFile来构建自己的镜像,其中DockerFile中的每个指令都会在镜像中创建一个层。当需要更改Docker并重建镜像时,仅需要重建那些已更改的层。与其他虚拟化技术相比,这是使镜像如此轻巧,小型和快速的部分原因。

3.5. Docker容器

Docker容器是Docker镜像运行的实例。我们可以使用Docker客户端来创建、启动、停止、删除容器,也可以将容器连接到一个或者多个网络,将存储连接到,甚至根据当前的状态来创建新镜像(docker build)

其中,值得注意的是,如果删除容器后,没有存储在磁盘中的数据将会永久消失。

综上,其他Docker 仓库、镜像和容器之间的关系可以类比Java中的面向对象。

其中,Docker仓库就是我们的大脑,当我们需要一个User类或者Tiger类时,我们就会从我们的大脑仓库中去寻找,当找到是,我们就是在我们的程序中写出User类和Tiger类,这些类就是Docker中的镜像,而当我们使用这些类时,我们就需要new出这些类的实例来,这些类的实例就是Docker中的容器。这样,我们就能简单的区分Docker中这三个重要的概念。

4. Docker原理

4.1. Docker的容器隔离

Docker使用一种称为 namespaces 来提供容器的隔离技术,运行容器时,Docker会为该容器创建一组 namespaces。这些 namespaces 提供了一层隔离。

4.2. 为什么Docker比VM快

(1)docker有着比虚拟机更少的抽象层。由亍docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。

(2)docker利用的是宿主机的内核,而不需要Guest OS。因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。仍而避免引寻、加载操作系统内核返个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,返个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返个过程,因此新建一个docker容器只需要几秒钟。

图片

图片

2019-08-11 19:00:23 hxy090 阅读数 37
  • 基于Docker的微服务实战 - Spring Cloud为例

    基于Docker的微服务实战视频教程,Docker技术的一致性交付能力和应用隔离使得它成为微服务实践中的重要一环。本次分享讨论微服务架构的特点,基于Docker构建一个微服务应用,并给出一个Spring Cloud应用示例。

    12054 人正在学习 去看看 CSDN讲师

1.Docker容器的工作原理

1.1docker是什么

docker使用Google推出的Go语言开发,基于linux的cgroup(cgroup将应用程序限制为特定的资源集,允许Docker Engine将可用的硬件资源共享给容器,并可选择强制执行限制和约束),namespace(运行容器时,Docker会为该容器创建一组 名称空间。这些命名空间提供了一层隔离,容器的每个方面都在一个单独的命名空间中运行,其访问权限仅限于该命名空间),联合文件系统UnionFS以及变体AUFS等技术。对进程进行封装隔离,属于操作系统层面的虚拟化技术,由于隔离的进程独立于宿主和其它的隔离的进程,因此也称之为容器。

1.2docker的概念理解

Docker镜像是一个特殊的文件系统,提供容器运行时所需的程序、库、资源、配置等文件外,还包含为运行时准备的一些配置参数(如匿名卷、环境变量、用户等),Docker镜像不包含任何动态数据,其内容在构建后不会被改变,它是创建容器的模板。由于镜像包含操作系统完整的root文件系统,其体积一般很庞大,因此Docker设计时设计为分层存储的架构。镜像只是一个虚拟概念,其实际体现并非由一个文件组成,而是由多层文件系统联合组成。

Docker容器是镜像的运行时实例,适用于基于Linux和Windows的应用程序,无论基础架构如何,容器化软件都将始终运行相同。容器将软件与其环境隔离开来,并确保它可以统一运行。每一个容器运行时是以镜像为基础层在其上创建一个当前容器的存储层,可以称为容器存储层。容器存储层的生存周期和容器一样,随着容器的消亡而消亡。因此任何保存于容器存储层的信息都会随容器删除而丢失。按照Docker最佳实践的要求,容器不应该向其存储层写入任何数据,应该使用volume数据卷或绑定宿主目录,这样性能和稳定性更高。

Docker仓库是一个集中存储、分发镜像的服务,Docker Registry就是这样的服务。一个Docker Registry可以包含多个仓库(Repository),每个仓库可以包含多个标签(Tag),每个标签对应一个镜像。一个仓库通常包含同一软件不同版本的镜像,可以通过<仓库名>:<标签>指定镜像的版本。如果不给出标签,默认标签为latest。

1.3docker工作原理

Docker 架构
在这里插入图片描述
Docker使用客户端 - 服务器(C/S)架构,使用远程API管理和创建Docker 容器。Docker 客户端与Docker 守护进程通信,后者负责构建,运行和分发Docker容器。Docker客户端和守护进程可以在同一系统上运行,也可以将Docker客户端连接到远程Docker守护进程。Docker客户端和守护进程使用REST API,通过UNIX套接字或网络接口进行通信。

Client
客户端通过命令行或其他工具与守护进程通信,客户端会将这些命令发送给守护进程,然后执行这些命令。命令使用Docker API,Docker客户端可以与多个守护进程通信。

Docker daemon
Docker守护进程(docker daemon)监听Docker API请求并管理Docker对象,如镜像,容器,网络和卷。守护程序还可以与其他守护程序通信以管理Docker服务。

Docker Host
Docker Host是物理机或虚拟机,用于执行Docker守护进程的仓库。

Docker Registry
Docker仓库用于存储Docker镜像,可以是Docker Hub这种公共仓库,也可以是个人搭建的私有仓库。使用docker pull或docker run命令时,将从配置的仓库中提取所需的镜像。使用docker push命令时,镜像将被推送到配置的仓库。

2.docker安装

使用的环境ubuntu19.04
1.如果安装过先删除老的版本(可忽略)

sudo apt-get remove docker docker-engine docker.io containerd runc

2.更新软件包

sudo apt-get update/sudo apt update

3.安装需要的包( HTTPS 传输的软件包, CA 证书等)

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

4.添加 GPG 密钥并添加 Docker-ce 软件源

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo  apt-key add -

验证是否添加成功(可忽略)

sudo apt-key fingerprint 0EBFCD88

在这里插入图片描述

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

5.添加成功后更新软件包缓存

sudo apt-get update

6.安装docker

 sudo apt-get install docker-ce

如果遇到如下错误
在这里插入图片描述
解决办法

cd /etc/apt/sources.list.d
sudo vi docker.list

添加内容

deb https://download.docker.com/linux/ubuntu zesty edge

7.验证
查看是否启动

systemctl status docker

在这里插入图片描述
通过helloworld镜像验证

sudo docker run hello-world

在这里插入图片描述
有以上输出安装成功

8.查看正在运行的容器

sudo docker ps -ls

9.查看镜像

sudo docker images

10.创建docker用户组避免使用sudo

sudo usermod -aG docker your-user

以上为ubuntu环境下docker安装相关

参考文档
https://docs.docker.com/engine/docker-overview/#docker-architecture
https://docs.docker.com/install/linux/docker-ce/ubuntu/

2018-04-17 14:58:16 luoliang2012 阅读数 824
  • 基于Docker的微服务实战 - Spring Cloud为例

    基于Docker的微服务实战视频教程,Docker技术的一致性交付能力和应用隔离使得它成为微服务实践中的重要一环。本次分享讨论微服务架构的特点,基于Docker构建一个微服务应用,并给出一个Spring Cloud应用示例。

    12054 人正在学习 去看看 CSDN讲师

Docker底层实现主要基于LINUX技术,包含LINUX上的命名空间(Namespaces)、控制组(Control groups)、Union文件系统(Union file system)。


  1. 命名空间。权限隔离控制,保证虽然在同一个宿主机上,但是相互是透明的。
  2. 控制组。资源分配,保证各个容器资源的分配管理。
  3. 联合文件系统。主要使用到cow技术(Copy on write),提高磁盘利用率。docker镜像,镜像可以通过分层来进行继承。支持将不同目录挂载到同一个虚拟文件系统下,Docker 中使用的 AUFS(AnotherUnionFS)就是一种联合文件系统。 AUFS 支持为每一个成员目录(类似 Git 的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限, 同时 AUFS 里有一个类似分层的概念, 对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)。

Docker基本操作

阅读数 1213

没有更多推荐了,返回首页