docker-基础

docker

# Docker导学

到底什么是Docker?

Docker能干什么?

  • 简化配置
  • 整合服务器
  • 代码流水线管理
  • 调试能力
  • 提高开发效率
  • 多租户
  • 隔离应用
  • 快速部署

容器时代的"双城记"

  • Docker
  • Kubernetes

大海航行靠舵手-Kubernetes

DevOps = 文化 + 过程 + 工具

# 容器技术概述

Long Long Time Ago

虚拟化技术出现以后

虚拟化的优点

  • 资源池-一个物理机的资源分配到了不同的虚拟机里
  • 很容易扩展-加物理机or加虚拟机
  • 很容易云化-亚马逊AWS,阿里云等

虚拟化的局限性

  • 每一个虚拟机都是一个完整的操作系统,要给其分配资源,当虚拟机数量增多时,操作系统本身消耗的资源势必增多

开发和运维面临的挑战 容器解决了什么问题?

  • 解决了开发和运维之间的矛盾

  • 在开发和运维之间搭建了一个桥梁,是实现devops的最佳解决方案

什么是容器?

容器和虚拟机的区别

虚拟机 + 容器

Docker - 容器技术的一种实现

# Docker架构和底层技术简介

Docker Platform

  • Docker提供了一个开发,打包,运行app的平台
  • 把app和底层infrastructure隔离开来

Docker Engine

Docker Architecture

底层技术

  • Namespaces:做隔离pid,net,ipc,mnt,uts
  • Control groups:做资源限制
  • Union file systems:Container和image的分层

# 在centos上安装docker

安装

sudo yum remove docker \
docker-common \
docker-selinux \
docker-engine

sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2

sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

sudo yum install docker-ce
1
2
3
4
5
6
7
8
9
10
11
12
13
14

启动

sudo systemctl start docker
sudo docker version
1
2

helloworld

sudo docker run hello-world
1

# Docker Image概述

什么是Image

Image的获取(1)

Image的获取(2)

// 查看进程
ps -ef | grep docker
// 查看镜像
sudo docker image ls
// 拉取镜像
sudo docker pull ubuntu:14.04
// 运行镜像
docker run hello-world
docker run -it centos
// 删除镜像
docker image rm 67759a80360c(镜像ID)
docker image rmi f2a91732366c(镜像ID)
1
2
3
4
5
6
7
8
9
10
11
12

# DIY一个Base Image

自己实现helloworld

mkdir hello-world
cd hello-world/
vim hello.c

// 内容
#include<stdio.h>

int main() {
  printf("hello docker\n");
}

gcc -static hello.c -o hello
1
2
3
4
5
6
7
8
9
10
11
12
vim Dockerfile

// 内容
FROM scratch
ADD hello /
CMD ["/hello"]
1
2
3
4
5
6
docker build -t brotherc/hello-world .
docker run brotherc/hello-world
1
2

# 初始container

什么是Container

docker container ls
docker container ls -a
docker container ps -a
docker rm $(docker container ls -f "status-exited" -q)
docker rm $(docker container ls -aq)
docker container rm 846b5efe98d4(容器ID)
docker container rm 84(容器ID前缀)
// 将已有容器提交成新的镜像
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] [flags]
docker commit xenodochial_pare(容器名称) brotherc/centos-vim
docker stop 容器id或名称
docker start 容器id或名称
docker inspect 容器id或名称
docker logs 容器id或名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 构建自己的Docker镜像

基于已经存在的container创建一个image

// 运行一个已安装好vim的centos容器
docker run -it centos
yum install -y vim
exit
1
2
3
4
// 容器名:xenodochial_pare
docker commit xenodochial_pare brotherc/centos-vim
1
2

基于Dockerfile创建一个image

mkdir docker-centos-vim
cd docker-centos-vim/
vim Dockerfile

FROM centos
RUN yum install -y vim

docker build -t brotherc/centos-vim-new .
1
2
3
4
5
6
7
8

# Dockerfile语法梳理

FROM 尽量使用官方的image作为base image!

FROM scratch #制作base image
FROM centos  #使用base image
FROM ubuntu:14.04
1
2
3

LABEL Metadata不可少!

LABEL maintainer="brotherc@136.com"
LABEL version="1.0"
LABEL description="This is description"
1
2
3

RUN 为了美观,复杂的RUN请用反斜杠换行!避免无用分层,合并多条命令成一行!

RUN yum update && yum install -y vim \ #反斜线换行
    python-dev
1
2
RUN apt-get update && apt-get install -y perl \
    pwgen --no-install-recommends && rm -rf \
    /var/lib/apt/lists/* #注意清理cache
1
2
3
RUN /bin/bash -c'source $HOME/.bashrc;echo $HOME'
1

WORKDIR 设定当前工作目录,类似cd 用WORKDIR,不要用RUN cd!尽量使用绝对目录!

WORKDIR /root
1
WORKDIR /test #如果没有会自动创建test目录
WORKDIR demo
RUN pwd       #输出结果应该是 /test/demo
1
2
3

ADD and COPY 将本地文件添加到image里面 大部分情况,COPY优于ADD!ADD除了COPY还有额外功能(解压)!添加远程文件/目录 请使用curl或者wget!

ADD hello /
1
ADD test.tar.gz / #添加到根目录并解压
1
WORKDIR /root
ADD hello test/ # /root/test/hello
1
2
WORKDIR /root
COPY hello test/
1
2

ENV 尽量使用ENV增加可维护性!

ENV MYSQL_VERSION 5.6 #设置常量
RUN apt-get install -y mysql-server="${MYSQL_VERSION}" \
    && rm -rf /var/lib/apt/lists/* #引用常量
1
2
3

RUN vs CMD vs ENTRYPOINT RUN:执行命令并创建新的image layer CMD:设置容器启动后默认执行的命令和参数 ENTRYPOINT:设置容器启动时运行的命令 Shell格式

RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"
1
2
3
FROM centos
ENV name Docker
ENTRYPOINT echo "hello $name"
1
2
3

Exec格式

RUN ["apt-get", "install", "-y", "vim"]
CMD ["/bin/echo", "hello docker"]
ENTRYPOINT ["/bin/echo", "hello docker"]
1
2
3
FROM centos
ENV name Docker
ENTRYPOINT ["/bin/echo", "hello docker"]
1
2
3

# Dockerfile最佳实践

Dockerfile:

FROM centos
ENV name Docker
ENTRYPOINT echo "hello $name"
1
2
3
docker build -t brotherc/centos-entrypoint-shell .
docker run brotherc/centos-entrypoint-shell
hello Docker
1
2
3

Dockerfile:

FROM centos
ENV name Docker
ENTRYPOINT ["/bin/bash", "-c", "echo hello $name"]
1
2
3
docker build -t brotherc/centos-entrypoint-exec .
docker run brotherc/centos-entrypoint-exec
hello Docker
1
2
3

CMD 容器启动时默认执行的命令 如果docker run指定了其它命令,CMD命令被忽略 如果定义了多个CMD,只有最后一个会执行 Dockerfile:

FROM centos
ENV name Docker
CMD echo "hello $name"
1
2
3
docker build -t brotherc/centos-cmd-shell .
docker run brotherc/centos-cmd-shell
hello Docker

docker run -it brotherc/centos-cmd-shell /bin/bash
无输出
1
2
3
4
5
6

ENTRYPOINT 让容器以应用程序或者服务的形式运行 不会被忽略,一定会执行

docker run brotherc/centos-entrypoint-shell
hello Docker

docker run -it brotherc/centos-entrypoint-shell /bin/bash
hello Docker

1
2
3
4
5
6

# 镜像的发布

docker login
docker push DockerId/镜像名称
docker pull DockerId/镜像名称
1
2
3

分享产生image 把我们的账户link到github或bitbucket,在github上面创建一个代码仓库,把我们的dockerfile push上去,这样就做了一个关联。 只要我们这个仓库里面有dockerfile,就会自动去克隆获取到这个dockerfile然后dockerhub后台服务器会帮我们去build。 这样我们既提供了dockerfile,docker image又是dockerhub后台服务器帮我们build的,这个安全性会有很大的提升。

私有的registry

docker run -d -p 5000:5000 --restart always --name registry
// 访问ip:5000
1
2

/etc/docker/daemon.json:

{"insecure-registries":["ip:5000"]}
1

/lib/systemd/system/docker.service:

sudo service docker restart
1
telnet ip:5000

docker push ip:5000/镜像名称
docker pull ip:5000/镜像名称
1
2
3
4

# Docker Network

基础网络概念

基于数据包的通信方式

网络的分层

路由的概念

IP地址和路由

公有IP和私有IP

  • Public IP:互联网的唯一标识,可以访问internet

  • Private IP:不可在互联网上使用,仅供机构内部使用

    A类 10.0.0.0--10.255.255.255 (10.0.0.0/8)

    B类 172.16.0.0--172.31.255.255 (172.16.0.0/12)

    C类 192.168.0.0--192.168.255.255 (192.168.0.0/16)

网络地址转换NAT

Ping和telnet

  • Ping(ICMP):验证IP的可达性

  • telnet:验证服务的可用性

sudo docker run -d --name test1 busybox /bin/sh -c "while true; do sleep 3600; done"
sudo docker exec -it test1 /bin/sh

ip a
1
2
3
4
sudo docker run -d --name test2 busybox /bin/sh -c "while true; do sleep 3600; done"
sudo docker exec test2 ip a
1
2

Linux Network Namespace

Bridge Network

Container Port Map

# Docker的持久化存储和数据共享

Container Layer

Data Volume

Docker持久化数据的方案

  • 基于本地文件系统的Volume。可以在执行Docker create或Docker run时,通过-v参数将主机的目录作为容器的数据卷。这部分功能便是基于本地文件系统的volume管理。
  • 基于plugin的Volume,支持第三方的存储方案,比如NAS,aws

Volume的类型

  • 受管理的data Volume,由docker后台自动创建。
  • 绑定挂载的Volume,具体挂载位置可以由用户指定。

数据持久化:Data Volume

//mysql镜像会默认将数据挂载到本地
sudo docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
1
2
sudo docker volume ls

DRIVER        VOLUME NAME
local         e6ee5901156...

sudo docker volume inspect e6ee5901156...
1
2
3
4
5
6
sudo docker stop mysql1
sudo docker rm mysql1
sudo docker volume ls

DRIVER        VOLUME NAME
local         e6ee5901156...

1
2
3
4
5
6
7
//给volume指定名字
sudo docker run -d -v mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
sudo docker volume ls

DRIVER        VOLUME NAME
local         mysql
1
2
3
4
5
6
//让mysql容器使用已存在的volume
sudo docker rm -rf mysql1
sudo docker run -d -v mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
1
2
3

数据持久化:Bind Mouting Dockerfile:

FROM nginx:latest
WORKDIR /usr/share/nginx/html
COPY index.html index.html
1
2
3
docker build -t brotherc/my-nginx .
docker run -d -p 80:80 --name web brotherc/my-nginx
1
2
docker rm -f web
docker run -d -v $(pwd):/usr/share/nginx/html -p 80:80 --name web brotherc/my-nginx
docker exec -it web /bin/bash
//在容器中
cd /usr/share/nginx/html
touch test.txt
exit
//在linux中看到刚刚创建的test.txt文件
1
2
3
4
5
6
7
8