Docker初体验

Docker这玩意流行已经有一阵子,之前一直不愿意去碰它,是觉得它还不够稳定。虽说各类软文铺天盖地,什么Paas微服务,容器引擎,轻量级虚拟机(当然底层的cgroups,lxc技术早已耳熟能详)等等,对这些往往不置可否,原因只有一个:大规模工业级场景应用还未曾出现,或者说未曾亲历。

时间来到了最近,由于工作需求,需要做一些MQ镜像,所以系统化的学习了Docker(当然,催生我系统化学习的动力不仅是要深度使用它,还有Go语言这两年本身的实践魅力)。这篇文章简单记录了Docker的一些使用心得及其感受,欢迎大家轻拍。

Docker安装

作为忠实的Linuxer,Ubuntu是我最钟爱的办公平台,当然自己的实践也是基于该平台的,如果是其它平台,请查看我参考文档里面的那几个在线文章。安装脚本如下:

sudo sh -c "echo deb http://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
sudo apt-get update
apt-get install lxc-docker

对使用者来说,docker遵循C/S架构模式,最新版本为1.4.1,如:

Client version: 1.4.1
Client API version: 1.16
Go version (client): go1.3.3
Git commit (client): 5bc2ff8
OS/Arch (client): linux/amd64
Server version: 1.4.1
Server API version: 1.16
Go version (server): go1.3.3
Git commit (server): 5bc2ff8

但是,每次敲docker命令都得带sudo,非常扰人,执行脚本如下:

sudo groupadd docker
# 添加当前用户到docker用户组里,这里我是以von登陆的
sudo gpasswd -a von docker
sudo service docker restart
docker version
#若未生效,则系统重启
sudo reboot

备注:为什么这么玩可以?官方文档是这么讲的

Giving non-root access

The docker daemon always runs as the root user, and since Docker version 0.5.2, the docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root, and so, by default, you can access it with sudo.

Starting in version 0.5.3, if you (or your Docker installer) create a Unix group called docker and add users to it, then the docker daemon will make the ownership of the Unix socket read/writable by the docker group when the daemon starts. The docker daemon
must always run as the root user, but if you run the docker client as a user in the docker group then you don‘t need to add sudo to all the client commands. As of 0.9.0, you can specify that a group other than docker should own the Unix socket with the -G
option.

Warning: The docker group (or the group specified with -G) is root-equivalent; see Docker Daemon Attack Surface details.

一旦安装ok,找个官方Helloworld示例玩玩,执行如下命令:

docker pull learn/tutorial
docker run learn/tutorial /bin/echo hello world

Docker体系结构及其核心技术

与whole-system virtualizers(比方说VMware ESXi, QEMU 或者Hyper-V) 和 paravirtualizers 技术(比方说Xen)等虚拟化技术不同, Docker核心是一个操作系统级虚拟化方案, 如下图所示:

Docker的后端是一个松耦合架构,模块各司其职,并有机组合,支撑Docker的运行。整体架构如下图所示:

用户使用Docker Client与Docker Daemon建立通信,并发送请求给后者。

而Docker Daemon作为Docker架构中的主体部分,首先提供Server的功能使其可以接受Docker Client的请求;而后Engine执行Docker内部的一系列工作,每一项工作都是以一个Job的形式的存在。

Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动graphdriver将下载镜像以Graph的形式存储;当需要为Docker创建网络环境时,通过网络管理驱动networkdriver创建并配置Docker容器网络环境;当需要限制Docker容器运行资源或执行用户指令等操作时,则通过execdriver来完成。

而libcontainer是一项独立的容器管理包,networkdriver以及execdriver都是通过libcontainer来实现具体对容器进行的操作。

当执行完运行容器的命令后,一个实际的Docker容器就处于运行状态,该容器拥有独立的文件系统,独立并且安全的运行环境等。每个用户实例之间相互隔离, 互不影响。它是如何做到的呢?一般的硬件虚拟化方法给出的方法是VM,而Docker靠的是kernel namespace。其中pid、net、ipc、mnt、uts、user等namespace将container的进程、网络、消息、文件系统、UTS("UNIX Time-sharing System")和用户空间隔离开。

下面简单介绍下这几块:

(1) pid namespace

不同用户的进程就是通过pid namespace隔离开的,且不同 namespace 中可以有相同pid。所有的LXC进程在docker中的父进程为docker进程,每个lxc进程具有不同的namespace。同时由于允许嵌套,因此可以很方便的实现 Docker in Docker。

(2) net namespace

有了 pid namespace, 每个namespace中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过net namespace实现的, 每个net namespace有独立的 network devices, IP addresses, IP routing tables, /proc/net 目录。这样每个container的网络就能隔离开来。docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge: docker0连接在一起。

(3) ipc namespace

container中进程交互还是采用linux常见的进程间交互方法(interprocess communication - IPC), 包括常见的信号量、消息队列和共享内存。然而同 VM 不同的是,container 的进程间交互实际上还是host上具有相同pid namespace中的进程间交互,因此需要在IPC资源申请时加入namespace信息 - 每个IPC资源有一个唯一的 32 位 ID。

(4) mnt namespace

类似chroot,将一个进程放到一个特定的目录执行。mnt namespace允许不同namespace的进程看到的文件结构不同,这样每个 namespace 中的进程所看到的文件目录就被隔离开了。同chroot不同,每个namespace中的container在/proc/mounts的信息只包含所在namespace的mount point。

(5) uts namespace

UTS("UNIX Time-sharing System") namespace允许每个container拥有独立的hostname和domain name, 使其在网络上可以被视作一个独立的节点而非Host上的一个进程。

(6) user namespace

每个container可以有不同的 user 和 group id, 也就是说可以在container内部用container内部的用户执行程序而非Host上的用户。

Docker实践要点

1. 基于已有包含JDK的image做增量镜像

why?自己做的Oracle JDK镜像大小和官方dockerfile/java差不多,700多兆,如果是OpenJDK,会小一些,大概500多兆。其次,自制脚本不好写,不过不用担心,我已经琢磨过了,脚本见后面,供大家参考。最后的问题,就是天朝网络慢,JDK压缩包经常下不下来。。。

2.detach from 容器 back to your terminal (不停止容器),请使用CTRL+P或者CTRL+Q

3. CMD 与 ENTRYPOINT 指令的区别(共同点:只会执行Dockfile中最后一个CMD和ENTRYPOINT命令)

CMD指令:The main purpose of a CMD is to provide defaults for an executing container.

用法如下:

CMD ["executable","param1","param2"] (exec form, this is the preferred form)

CMD ["param1","param2"] (as default parameters to ENTRYPOINT)

CMD command param1 param2 (shell form)

第一种用法:运行一个可执行的文件并提供参数。

第二种用法:为ENTRYPOINT指定参数。

第三种用法(shell form):是以”/bin/sh -c”的方法执行的命令。

注意:docker run命令如果指定了参数会把CMD里的参数覆盖

ENTRYPOINT指令: An ENTRYPOINT allows you to configure a container that will run as an executable.

用法如下:

ENTRYPOINT ["executable", "param1", "param2"] (the preferred exec form)

ENTRYPOINT command param1 param2 (shell form)

注意:第二种用法会屏蔽掉docker run时后面加的命令和CMD里的参数

4. 官方目前存在两个主要的JDK版本镜像(https://registry.hub.docker.com/search?q=java)。通常情况下,我会选择Oracle JDK版本,即dockerfile / java,但是该文件镜像很大,自己试图制作一个Oracle JDK7镜像,发现体积和官方差不多,700多兆。纯净的Ubuntu镜像200多兆,装一个JDK,暴增到700多兆,多么痛的领悟啊。附注自己JDK镜像Dockefile,欢迎大家复用脚本:

############################################################
# Dockerfile to run RocketMQ Containers
# Based on Ubuntu Image
############################################################

# Set the base image to use to Ubuntu
FROM ubuntu

# Set the file maintainer (your name - the file's author)
MAINTAINER gosling  "<span style="font-family: Arial, Helvetica, sans-serif;">gosling</span>@gmail.com"

# Update package repository
RUN echo "deb http://archive.ubuntu.com/ubuntu trusty main universe" > /etc/apt/sources.list
RUN apt-get update -y

# Install python tools (so you can do add-apt-repository)
RUN apt-get install -y -q python-software-properties software-properties-common

#Install Oracle jdk7
#RUN #  echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && # add-apt-repository ppa:webupd8team/java -y && #  apt-get update -y && #  apt-get install oracle-java8-installer -y && #  apt-get clean && #  update-alternatives --display java && #  echo "JAVA_HOME=/usr/lib/jvm/java-8-oracle" >> /etc/environment

RUN      add-apt-repository ppa:webupd8team/java -y &&      apt-get update -y &&      echo oracle-java7-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections &&      apt-get -y install oracle-java7-installer &&       apt-get clean &&      update-alternatives --display java &&      echo "JAVA_HOME=/usr/lib/jvm/java-7-oracle" >> /etc/environment

WORKDIR /data

CMD ["bash"]

5. 使用NC上传文件

镜像中没有vim,没法编辑/etc/hosts,现在本地有一份,想上传上去:

首先映射端口(主机的9999端口和container的9999端口):

   docker run -i -t -p 22222:33333 ubuntu /bin/bash

其次,container上监听9999:

nc -l -p 9999 > /etc/hosts

最后,本地使用9999端口传输:

   nc localhost 9999 < /etc/hosts

6. 使用Docker exec 还是集成sshd

参考官方博客,http://blog.docker.com/2014/06/why-you-dont-need-to-run-sshd-in-docker/

参考文章

1. Docker中文指南, http://www.widuu.com/chinese_docker/installation/ubuntu.html

2. Docker从入门到实践, http://yeasy.gitbooks.io/docker_practice/

3. Dockerfile 最佳实践, https://docs.docker.com/articles/dockerfile_best-practices/

4. Ubuntu Docker安装, https://docs.docker.com/installation/ubuntulinux/#ubuntu-trusty-1404-lts-64-bit

5. Docker如何去掉sudo, https://docs.docker.com/installation/ubuntulinux/#giving-non-root-access

6. 操作系统虚拟化方案, http://en.wikipedia.org/wiki/Operating-system-level_virtualization

7. Docker源码分析, http://www.infoq.com/cn/articles/docker-source-code-analysis-part1

8. Docker技术预览, http://www.infoq.com/cn/articles/docker-core-technology-preview

时间: 2024-10-09 20:18:47

Docker初体验的相关文章

Docker学习系列(二)Docker初体验

一.系统要求 Docker的安装,需要在CentOS 7.0+版本,内核至少3.10,64-bit uname --r [[email protected] ~]$ uname --r 3.10.0-514.6.2.el7.x86_64 [[email protected] ~]$ 二.更新YUM yun update 三.新建Docker repository 在 /etc/yum.repos.d/下新建一个文件docker.repo,内如如下 [dockerrepo] name=Docker

docker初体验:Docker部署SpringCloud项目eureka-server

Docker部署SpringCloud项目eureka-server 1 创建eureka-server工程 创建父工程cloud-demo,其pom.xml如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLS

Docker深入浅出系列 | 容器初体验

Docker深入浅出系列 | 容器初体验 教程目标 Docker已经上市很多年,不是什么新鲜事物了,很多企业或者开发同学以前也不多不少有所接触,但是有实操经验的人不多,本系列教程主要偏重实战,尽量讲干货,会根据本人理解去做阐述,具体官方概念可以查阅官方文档,本章目标如下: 了解什么是Docker 了解Docker解决了什么 了解什么是镜像和容器 了解容器与虚拟机的区别 了解Vagrant与Docker的区别 了解Docker引擎和架构 了解Docker的镜像分层 了解VirturalBox和Do

erlang 初体验

最近测试了一下 erlang的坑... 如不出意外.... 大家第一眼看到这语法... 心里第一句一定是"我擦.这TM都是啥!!!!!" 没有变量!!! 没有结构体!!! 没有循环!!! 好吧,至少我是这样想的. 找了半天..连个if也不知道怎么写.. 这记录一些基本常识.. -module(module_name)  %%定义模块 括号内的要和文件名相同. -export([fun1/1 fun2/2]) %%这里是导出2个函数对外使用  函数名/参数名. 一个简单的函数定义如下 f

linux初体验

第一次听到linux这个'词语'是在一次偶然的朋友聊天中朋友提到的,之前压根没听到过'这个东西',所以我可以说是个linux的新新手,菜鸟都不算. 截至到目前,我已经开始linux系统运维学习有差不多10天时间了.在没接触linux之前,我对它的认识仅仅是:它是个计算机系统.决定学习linux系统运维之前,自我以为运维应该是对系统的一些日常维护之类的,不会很难的东西,我更希望运维是个不难的东西,我个人很笨,对难的东西可能接受的很慢,所以我愿意认为运维是很简单的,这样我就可以轻轻松松的掌握运维相关

【Spark深入学习 -15】Spark Streaming前奏-Kafka初体验

----本节内容------- 1.Kafka基础概念 1.1 出世背景 1.2 基本原理 1.2.1.前置知识 1.2.2.架构和原理 1.2.3.基本概念 1.2.4.kafka特点 2.Kafka初体验 2.1 环境准备 2.2 Kafka小试牛刀 2.2.1单个broker初体验 2.2.2 多个broker初体验 2.3 Kafka分布式集群构建 2.3.1 Kafka分布式集群构建 2.3.2 Kafka主题创建 2.3.3 生产者生产数据 2.3.4消费者消费数据 2.3.5消息的

Java8初体验(二)Stream语法详解

原文链接:http://ifeve.com/stream/ 1. Stream初体验 我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel aggregate operations. 我们来解读一下上面的那句话: Stream是元素的集合,这点让Stream看起来用些类似Iterator: 可以支持顺序和并行的对原Stream进行汇聚的操作: 大家可以把Stream当成一个高级版本的

hibernate--CRUD初体验

hibernate的crud操作初体验. 看具体实例 package com.fuwh.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import org.hibernate.annotations.GenericGenerator; @Entity publ

Oracle SQL篇(一)null值之初体验

    从我第一次正式的写sql语句到现在,已经超过10年的时间了.我写报表,做统计分析和财务对账,我一点点的接触oracle数据库,并尝试深入了解.这条路,一走就是10年,从充满热情,到开始厌倦,我不知道我还能坚持多久,未来的路,谁知道呢? 也许是该抓紧时间,做一点什么了,我不知道该开始写些什么,我从来没有在网上写东西的习惯.     先从简单的开始吧,那当然就是SQL,这是我SQL系列的第一篇,希望我能够坚持. 在Oracle数据库中,如果一个表中的列没有值的话,我们可以说是空值,比如IT员