Docker学习

一、Docker介绍

Docker镜像:使用docker把应用程序和依赖环境打包而成

Docker Container(容器):使用runtime启动起来的Docker镜像。

DevOps:为了解决开发交付与敏捷开发矛盾而形成的

13年成立,15年开始。

Docker1.8之前使用LXC:Linux内核接口,不支持跨平台

namespace和cgroup封装在libcontainer(支持跨平台)

OCI(open container initiative开放容器计划)组织。

libcontainer+CLI=runC与底层交互

containerd提供grpc接口,实现容器上的高级功能,比如镜像管理、容器执行的调用等

Dockerd目前是最上层与CLI交互的进程,接收Cli的请求并与containerd协作。

Docker是一种CS架构的软件产品,可以把代码与依赖打包成镜像,作为交付介质,并且把镜像启动成为容器,提供容器生命周期的管理。

runC和Containerd是docker的核心项目。

二、Docker安装

配置宿主机网卡转发

$ cat <<EOF > /etc/sysctl.d/docker.conf

net.bridge.bridge-nf-call-ip6tables = 1

net.bridge.bridge-nf-call-iptables = 1#二层网桥需要经过iptables过滤规则

net.ipv4.ip_forward=1#允许路由转发功能打开

$ sysctl -p /etc/sysctl.d/docker.conf#从指定文件加载系统参数

Yum安装配置docker

#下载阿里源repo文件

#curl -o 本地NewName  下载源地址

$ curl -o /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo

$ curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

$ yum clean all &&yum makecache

#yum会把下载下来的rpm包和header存储在cache中,不会自动清除。yum clean headers,yum clean packages

#yum makecache是把服务器的包信息下载到本地缓存起来。

$ yum install docker-ce -y

$ yum list docker-ce --showduplicates | sort -r#查看版本

$ yum install -y docker-ce-18.09.9#安装指定版本

#输出docker-ce的版本号并将数字当作字符进行排序,查看源中可用版本

安装最新版的19.03

#配置源加速器,docker镜像是在国外,阿里提供了一个加速镜像

https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors

mkdir -p /etc/docker

vi /etc/docker/daemon.json#进程加载时读这个文件

{

  "registry-mirrors":[

     "https://***.mirror.aliyuncs.com"

]

}

#设置开机自启

systemctl enable docker

systemctl daemon-reload

#启动docker

systemctl  start docker

#which docker环境变量里的docker文件

#ps aux|grep dockerd#查看进程docker是否启动

#journalctl -fu docker查看docker日志

#docker version查看docker版本

三、三大核心要素及常用操作详解

三大核心要素:镜像(Image)、容器(Container)、仓库(Registry)

仓库:存放镜像的地方

1)公有仓库Docker Hub、阿里、网易

2)私有仓库

  • Docker Registry,Docker官方提供的镜像仓库存储服务
  • Harbor,是Docker Registry的更高级封装,它除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能
  • 镜像访问地址形式registry.devops.com/demo/hello:latest,若没有前面的url地址,则默认寻找Docker Hub中的镜像,若没有tag标签,则使用latest作为标签。比如,docker pull nginx,会被解析成docker.io/library/nginx:latest
  • 公有的仓库中,一般存在这么几类镜像
    • 操作系统基础镜像(centos,ubuntu,suse,alpine)
    • 中间件(Nginx,redis,mysql,tomcat)
    • 语言编译环境(python,java,golang)
    • 业务镜像(django-demo...)

容器和仓库不会直接交互,都是以镜像为载体来操作。

2、基本命令

docker images#查看基础镜像列表

docker pull  nginx:alpine#拉取镜像alpine是版本

#本地构建

docker build . -t my-nginx:ubuntu -f Dockerfile

#如何通过镜像启动容器

docker run --name my-nginx-alpine -d nginx:alpine

#如何知道容器内部运行了什么程序?

#进入容器内部,分配一个tty终端

$ docker exec -ti my-nginx-alpine /bin/sh#进入容器

$ docker exec my-nginx-alpine ls#精准执行一个命令

$ docker ps#查看容器列表

$ pwd#当前所处目录/etc/docker

$ ps axu#查看系统进程 nginx -g daemon off;表示进入的是前台,daemon表示后台

$ exit#退出

#创建Dockerfile

#告诉docker使用哪个基础镜像作为模版,后续命令都以这个镜像为基础,ubuntu可以是镜像的地址

FROM ubuntu

#RUN命令会在上面指定的镜像里执行命令

RUN apt-get update && apt install -y nginx

#告诉docker,启动容器时执行如下命令

CMD ["/usr/sbin/nginx","-g","daemon off;"]

docker build . -t my-nginx:ubuntu -f Dockerfile#点是目录

宿主机中如何访问容器服务

$ docker rm -f my-nginx-alpine#删除旧服务

$ docker run --name my-nginx-alpine -d -p 8080:80 nginx:alpine#8080是宿主机,映射容器80端口

$ curl 192.168.1.12:8080

导出镜像到文件中

$ docker save -o nginx-alpine.tar nginx:alpine

从文件中加载镜像

$ docker load -i nginx-alpine.tar

commit、export不建议使用,没有历史记录,不能修改

$ docker info#docker信息

使用docker镜像启动镜像仓库服务 

$ docker run -d -p 5000:5000 -name registry registry:2#添加--restart always重启的时候,它会自动启动起来-d是后台启动

$ docker run --memory=500m nginx:alpine#资源限制,最大可用内存500M

docker  tag nginx:alpine localhost:5000/nginx:alpine#把本地的镜像推到registry仓库,tag理解为快捷方式

docker push localhost:5000/nginx:alpine#推到镜像仓库

查看仓库内镜像元数据

$ curl -X GET http://x.x.x.x:5000/v2/_catalog#访问镜像名称

$ curl -X GET http://x.x.x.x:5000/v2/nginx/tags/list#访问镜像和标签标签

#docker默认不允许向http的仓库地址推送,如何做成https的,参考:https://docs.docker.com/registry/deploying/#run-an-externally-accessible-registry

#我们没有可信任证书机构颁发的证书和域名,自签名证书需要在每个节点中拷贝证书文件,比较麻烦,因此问我我们通过配置daemon的方式,来跳过证书的验证

$ cat /etc/docker/daemon.json

{

        "registry-mirrors":["https://x.mirror.aliyuncs.com],

        "insecure-registries":["x.x.x.x:5000"]

}

$ systemctl restart docker#重启docker

$ docker ps -a#查看所有

$ docker start my-nginx-alpine#启动镜像

$ docker rmi localhost:5000/nginx:alpine#删除镜像

容器数据持久化

##挂载主机目录

$ docker run --name nginx -d -v /opt:/opt -v /var/log:/var/log nginx:alpine

$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d -v /opt/mysql/:/var/lib/mysql mysql:5.7#左边宿主机,右边容器

###使用volumes卷

$ docker volume ls

$ docker volume create my-vol

#同上,只是把磁盘换成了盘符卷来使用,不推荐

#验证数据共享

$ docker exec -ti nginx2 命令

进入容器或者执行容器内的命令

$ docker exec -ti <container_id_or_name> /bin/sh

$ docker exec <container_id_or_name> 命令

主机与容器之间拷贝数据

#主机拷贝到容器

$ docker cp /tmp/test.txt nginx:/tmp

#容器拷贝到主机

$ docker cp nginx:/tmp/test.txt ./

挂载已有的数据,重新创建镜像仓库容器 

$ scp -P 9000 /d/tmp/registry.tar.gz x.x.x.x:/tmp#复制文件

#解压离线镜像文件

tar zxf registry.tar.gz -C /opt

###删除当前镜像仓库容器

$ docker rm -f registry

##使用docker镜像启动镜像仓库服务

$ docker run -d -p 5000:5000 --restart always -v /opt/registry:/var/lib/registry --name registry registry:2

四、Django应用容器化实践

构建命令

$ docker build . -t ImageName:ImageTag -f Dockerfile

Dockerfile文件

#this my first django Dockerfile

#Version 1.0

#Base images 基础镜像

FROM centos:centos7.5.1804

#MAINTAINER维护者信息

LABEL maintainer="whoami@qq.com"

#ENV设置环境变量

ENV LANG en_US.UTF-8

ENV LC_ALL en_US.UTF-8

#RUN 执行一下命令

RUN curl -so /etc/yum.repos.d/Centos-7.repo http://mirrors.aliyun.com/repo/Centos-7.repo&& rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.e17.ngx.noarch.rpm

RUN yum install -y python36 python3-devel gcc pcre-devel zlib-devel make net-tools nginx

#工作目录

WORKDIR /opt/myblog

#拷贝文件至工作目录.是当前目录的所有,第二个.是容器工作目录

COPY . .

#拷贝nginx配置文件

COPY myblog.conf /etc/nginx

#安装依赖的插件

RUN pip3 install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt

RUN chmod +x run.sh && rm -rf ~/.cache/pip

RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache

#EXPOSE映射端口

EXPOSE 8002

#容器启动时执行命令

CMD ["./run.sh"]

run.sh文件

 #/bin/bash

uwsgi --ini ./uwsgi.ini

nginx -c /etc/nginx/myblog.conf -g "daemon off;'

requirements.txt文件

PyMySQL==0.9.3

Django==2.1.8

uwsgi==2.0.18

docker build . -t myblog:v1 -f Dockerfile

mysql应该和之前的镜像分开,因为它应该单进程运行 

$ docker run -d -p 3306:3306 --name mysql -v /opt/mysql:/var/lib/mysql -e MYSQL_DATABASE=myblog -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

启动Django应用

##启动容器

$ docker run -d -p 8002:8002 --name myblog -e MYSQL_HOST=x.x.x.x -e MYSQL_USER=root -e MYSQL_PASSWD=123456 myblog:v1

#创建超级用户

$ docker exec -ti myblog python3 manage.py createsuperuser 

##收集静态文件

$ docker exec -ti myblog python3 manage.py collectstatic

mysql重做镜像,否则配置每次都要进行挂载

#dockerfiles/mysql/Dockerfile文件

FROM mysql:5.7

COPY my.cnf /etc/mysql/my.cnf#添加本地文件到镜像和ADD功能一样,ADD多了解压

###CMD或者ENTRYPOINT默认继承 ,ENTRYPOINT先执行,则CMD作为参数传递

#删除旧的mysql容器,使用新镜像启动,不用再此初始化

docker build . -t mysql:5.7-utf8#-f Dockerfile假如名字默认是这个可以省略

docker tag mysql:5.7-utf8 xxx.xxx.xx.xx:5000/mysql:5.7-utf8

docker push xxx.xxx.xx.xx:5000/mysql:5.7-utf8#上传到仓库占空间,可以不push

docker rm -f mysql

rm -rf /opt/mysql/

docker run -d -p 3306:3306 --restart=always --name mysql -v /opt/mysql/:/var/lib/mysql -e MYSQL_DATABASE=myblog -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7-utf8

五、实现原理

虚拟化核心需要解决的问题:资源隔离和资源限制

  • 虚拟化硬件虚拟化技术,通过一个hypervisor层实现对资源的彻底隔离
  • 容器则是操作系统级别的虚拟化,利用的是内核的Cgroup和Namespace特性,此功能完全通过软件实现

1、Namespace资源隔离

命名空间是全局资源的一种抽象,将资源放到不同的命名空间中,各个命名空间中的资源是相互隔离的

分类系统调用参数相关内核版本
Mount namespacesCLONE_NEWNSLinux 2.4.19
UTS namespacesCLONE_NEWUTSLinux 2.6.19
IPC namespacesCLONE_NEWIPCLinux 2.6.19
PID namespacesCLONE_NEWPDLinux 2.6.24
Network namespacesCLONE_NEWNETLinux 2.6.24-2.6.29
User namespacesCLONE_NEWUSERLinux 2.6.23-3.8

echo $$#命名空间id

ls -l /proc/$$/ns#显示当前命名空间里的

docker在启动一个容器的时候,会调用linux kernel Namespace的接口,来创建一块虚拟空间,创建的时候,可以支持设置下面的这几种(可以随意选择),docker默认都设置。

  • pid:用于进程隔离(PID:进程ID)
  • net:管理网络接口(NET:网络)
  • ipc:管理对IPC资源的访问(IPC:进程间通信(信号量、消息队列和共享内存))
  • mnt:管理文件系统挂载点(MNT:挂载)
  • uts:隔离主机和域名
  • user:隔离用户和用户组

2、CGroup资源限制

通过namespace可以保证容器之间的隔离,但是无法控制每个容器可以占用多少资源,如果其中的某一个容器正在执行CPU密集型的任务,那么就会影响其他容器中任务的性能与执行效率,导致多个容器相互影响并且抢占资源。如何对多个容器的资源使用进行限制就成了解决进程虚拟资源隔离之后的主要问题。int clone()

Control Groups(简称CGroups)就是能够隔离宿主机器上的物理资源,例如CPU、内存、磁盘I/O和网路带宽。每一个CGroup都是一组被相同的标准和参数限制的进程。而我们需要做的,其实就是把容器这个进程加入到指定的Cgroup中。

3、UnionFS其实是一种为Linux操作系统设计的用于把多个文件系统联合到同一个挂载点的文件系统服务。它能够将不同文件夹中的层联合(Union)到了同一个文件夹中,整个联合的过程被称为联合挂载(Union Mount)

docker info#查看存储驱动storage driver

docker是分层读取的,Dockerfile每一个命令即是一层

六、网络模式

我们在使用docker run创建容器时,可以用--net选项指定容器的网络模式,Docker有以下四种网路模式:

  • bridge模式,使用--net=bridge指定,默认设置
  • host模式,使用--net=host指定,容器内部网络空间共享宿主机的空间,效果类似直接在宿主机上启动一个进程,端口信息和宿主机共用
  • container模式,使用--net=container:NAME_or_ID指定,指定容器与特定容器共享命名空间
  • none模式,使用--net=none指定,网络模式为空,即仅保留网络命名空间,但是不做任何网络相关的配置(网卡、IP、路由等)

1、bridge模式

网桥模式:可以看作一个二层交换机

Linux中能够起到虚拟交换机作用的网络设备,是网桥,它是一个工作在数据链路层(Data Link)的设备,主要功能是根据MAC地址将数据包转发到网桥的不同端口上。

yum install -y bridge-utils#没有的网桥,可以安装下,docker创建的时候创建

brctl show

brctl showmacs docker0#展示mac地址,虚拟网桥

route -n#展示网关

ip a#所有网卡

veth pair相当于一条网线

docker exec -ti test1 cat /sys/class/net/eth0/ifindex#查看网卡号

#主机中找到虚拟网卡后面的这个@ifxx的值,如果是同一个值,说明这个虚拟网卡和这个容器的eth0网卡是配对的

if a |grep @if

整理脚本,快速查看对应:

for container in $(docker ps -q);|do

        iflink=`docker exec -it $container sh -c 'cat /sys/class/net/eth0/iflink'`#容器网卡号

        iflink=`echo $iflink|tr -d '\r'`

        veth=`grep -l $iflink /sys/class/net/veth*/ifindex`

        veth=`echo $veth|sed -e 's;^.*net/\(.*\)/ifindex$;\1;'`

        echo $container:$veth

done

2、None模式

只会创建对应的网络空间,不会配置网络堆栈(网卡、路由等)

docker run -it --rm --name=network-none --net=none nginx:alpine sh#容器退出,容器直接会被删除

在宿主机中操作 

#创建虚拟网卡对

ip link add A type veth peer name B

#A端插入到docker0网桥

brctl addif docker0 A

ip link set A up

docker inspect network-none|grep -i pid#不区分大小写,输出pid

ll /proc/14464/ns#获取命名空间

ll /proc/$$/ns#宿主机命名空间

#在宿主机操作容器中的命名空间需要借助ip netns

ip netns list

#B端插入到network-none容器中,需要借助ip netns,因此需要显示的创建命名network namespace

PID=$(docker inspect -f '{{.State.Pid}}' network-none)#-f是go语言的格式化输出PID

mkdir -p /var/run/netns

ln -s /proc/$PID/ns/net /var/run/netns/$PID#建立软连接

#B端放到容器的命名空间

ip link set B netns $PID

ip netns exec $PID ip link set dev B name eth0#修改设备名称为eth0,和docker默认行为一致

ip netns exec $PID ip link set eth0 up

#设置ip

ip netns exec $PID ip addr add x.x.x.x/16 dev eth0

#添加默认路由,指定给docker0网桥

ip netns exec $PID ip route add default via x.x.x.x

docker inspect network-none|grep -i pid#查看容器进程id

iptables -t nat -nvL PREROUTING#查看iptables本地规则

ip route show table local type local#查看哪些包走了这个本地规则

iptables -t nat -nvL POSTROUTING# 出口链

SNAT#自动替换源地址,直接转换成出口的ip地址

抓包演示:

#首先访问宿主机的8088端口,我们抓一下宿主机的eth0

$ tcpdump -i eth0 port 8088 -w host.cap#抓包写到host.cap文件里

#容器内安装tcpdump

$ sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories#读文件写入后面的文件中

$ apk add tcpdump

$tcpdump -i eth0 port 80 -w container.cap

docker cp test:/文件名 ./#拷贝容器的文件到宿主机

scp -P 9000 172.21.51.67:/tmp/*.cap /tmp/

cap包可以在wireshark上进行合并包查看

3、Host模式

docker run --net host -d --name mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

容器启动后,会默认监听3306端口,由于网路模式上host,因为直接通过宿主机的3306端口进行访问服务,效果等同于在宿主机中直接启动mysqld的进程,共享网络端口,不建议使用

4、Container模式

docker run -ti --rm --net=container:mysql busyhox sh#共享网络命名空间(两个容器,k8s实现网络的形式)

docker rm $(docker ps -aq)#清理主机上所有退出的容器

docker run --rm -ti <image_id> sh#进入容器后,手动执行对应的ENTRYPOINT或者CMD命令,这样即使出错,容器也不会退出,因为bash作为1号进程,我们只要不退出容器,该容器就不会自动退出。

七、重装遇到的问题

重新安装docker,总是挂起状态。

/Applications/Docker.app/Contents/MacOS/Docker --uninstall

参考:Docker doesn't start (no GUI) · Issue #1326 · docker/for-mac · GitHub 

 

<think>嗯,用户想了解Docker学习路径。首先我得理清楚Docker的基础知识,然后分步骤来规划。可能用户是刚开始接触容器技术,需要从最基础的概念讲起。 首先应该介绍Docker是什么,为什么需要它。然后安装和环境配置,这部分可能需要涵盖不同操作系统的安装步骤,比如Windows、macOS和Linux。接着是基本命令,像镜像和容器的管理,这部分比较实用,用户可能需要实际操作例子。 接下来是Dockerfile和镜像构建,这是关键部分,用户需要学会如何自定义镜像。之后是数据管理和网络配置,这些在实际项目中很重要,比如卷的使用和容器间通信。然后是Docker Compose,处理多容器应用,用户可能会用到这个来部署复杂应用。 高级部分可能需要包括Docker Swarm和Kubernetes的基础,但用户可能暂时不需要太深入,可以简要提一下。最后是安全性和最佳实践,确保用户了解如何安全地使用Docker。 还要考虑用户可能的应用场景,比如开发、测试或者生产环境部署。可能需要推荐一些实践项目,比如搭建Web应用,帮助用户巩固知识。另外,学习资源方面,官方文档和社区资源很重要,可以推荐一些书籍或者在线课程。 需要检查是否有遗漏的部分,比如是否提到监控和日志管理,或者与其他工具集成,比如CI/CD。不过作为学习路径,可能先集中在核心内容,高级话题可以后续扩展。 最后,确保结构清晰,步骤由浅入深,让用户能够循序渐进地学习。避免使用过于专业的术语,保持解释的易懂性。同时,注意使用正确的Markdown格式,特别是数学公式部分,不过在这个问题中可能用不上,但需要遵守系统指令中的格式要求。</think>以下是分阶段Docker学习路径(建议配合实践操作): 一、基础入门阶段(1-2周) 1. 核心概念理解 - 容器与虚拟机的本质区别(资源隔离 vs 硬件虚拟化) - 镜像分层存储原理(联合文件系统) - 容器生命周期管理(创建→运行→停止→销毁) 2. 环境搭建 ```bash # Linux安装示例 curl -fsSL https://get.docker.com | bash -s docker sudo systemctl enable --now docker ``` 3. 基础指令实践 ```bash docker run -d -p 80:80 --name web nginx:alpine # 启动Nginx容器 docker exec -it web sh # 进入容器shell docker logs --tail 50 web # 查看日志 ``` 二、进阶应用阶段(2-4周) 1. Dockerfile编写技巧 ```dockerfile FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"] ``` 2. 数据持久化方案 ```bash docker volume create db-data docker run -d -v db-data:/var/lib/mysql mysql:8.0 ``` 3. 网络配置实践 ```bash docker network create app-net docker run -d --net=app-net --name db redis:6 docker run -d --net=app-net -p 8080:80 webapp ``` 三、生产级部署阶段(1-2个月) 1. Docker Compose编排 ```yaml version: '3.8' services: web: build: . ports: - "5000:5000" depends_on: - redis redis: image: "redis:alpine" ``` 2. 镜像优化策略 - 多阶段构建(减少最终镜像体积) - 安全扫描(使用docker scan) - 镜像签名验证 3. 容器监控方案 ```bash docker stats # 实时资源监控 docker run -d -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock dockersamples/visualizer ``` 四、持续学习建议 1. 官方文档精读(https://docs.docker.com) 2. 实验平台练习(推荐Play with Docker) 3. 参与社区项目(Docker GitHub仓库issue区) 4. 云原生技术延伸(Kubernetes、Service Mesh) 重点实践项目建议: 1. 构建完整LNMP环境 2. 实现CI/CD流水线 3. 搭建微服务架构演示系统 4. 容器安全加固实验 避坑指南: - 避免使用latest标签 - 容器内不要存储重要数据 - 生产环境限制容器资源配额 - 定期更新基础镜像版本 学习资源推荐: - 《Docker——容器容器云(第2版)》 - 极客时间《深入剖析Kubernetes》(前4章) - Docker官方认证课程(DCA) - Katacoda交互式学习平台 建议每天保持1小时实践时间,通过实际项目巩固知识体系。遇到问题时,善用docker inspect命令分析容器状态,多查阅Docker官方文档的CLI参考手册。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值