[工具]docker笔记

Docker 入门与实战指南

一、Docker 简介

Docker 是基于 Go 语言实现的云开源项目,其主要目标是“Build, Ship and Run Any App, Anywhere”,通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的 APP 及其运行环境做到一次镜像,处处运行。

二、传统虚拟机与容器对比

(一)传统虚拟机

传统虚拟机技术基于安装在主操作系统上的虚拟机管理系统(如 VirtualBox、VMware 等),创建虚拟机(虚拟出各种硬件),在虚拟机上安装从操作系统,在从操作系统中安装部署各种应用。其缺点是资源占用多、冗余步骤多、启动慢。

(二)Linux 容器(LXC)

Linux 容器是与系统其他部分分隔开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件。容器提供的镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。

三、Docker 优势

Docker 有比虚拟机更少的抽象层,运行在 Docker 容器上的程序直接使用的都是实际物理机的硬件资源,因此在 CPU、内存利用率上 Docker 有明显优势。Docker 利用的是宿主机的内核,而不需要加载操作系统 OS 内核。

四、Docker 基本组成部分

  • 镜像(image):Docker 镜像就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建多个容器。
  • 容器(container):Docker 利用容器独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。
  • 仓库(repository):Docker 仓库是集中存放镜像文件的场所。仓库分为公开仓库和私有仓库两种。

五、Docker 架构

Docker 是一个 C/S(Client-Server)结构的系统,后端是一个松耦合架构,众多模块各司其职。Docker 守护进程运行在主机上,然后通过 Socket 连接从客户端访问,守护进程从容器接收命令并管理运行在主机上的容器。

六、CentOS 安装 Docker

(一)卸载旧版本

如果之前安装过 Docker,需要先卸载旧版本:

sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

(二)配置 yum 资源库

安装 yum-config-manager:

sudo yum install -y yum-utils

配置 docker 的资源库地址:

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

(三)安装 Docker 引擎

安装最新版本的 Docker 引擎、Docker 客户端:

sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

(四)启动 Docker 引擎

sudo systemctl start docker

(五)卸载 Docker

  1. 关闭服务
sudo systemctl stop docker
  1. 使用 yum 删除 docker 引擎
sudo yum remove docker-ce docker-ce-cli containerd.io
  1. 删除镜像、容器、卷、自定义配置等文件
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

七、运行 HelloWorld 测试

docker run hello-world

八、Docker 下载加速

(一)使用网易数帆、阿里云等容器镜像仓库进行下载

例如,下载网易数帆镜像中的 mysql。

docker pull hub.c.163.com/library/mysql:latest

(二)配置阿里云加速

登录阿里云,进入工作台 -> 容器镜像服务 -> 镜像工具 -> 镜像加速器。里面提供了一个加速器地址,将该地址配置到 docker 中:

cd /etc/docker
vi daemon.json

在 daemon.json 中写入以下内容:

{
  "registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"]
}

然后刷新配置、重启 docker 即可:

sudo systemctl daemon-reload
sudo systemctl restart docker

九、Docker 配置代理

如果使用了科x学x上x网,可以为 docker 配置代理。在 /etc/docker/daemon.json 文件中加入以下内容:

{
  "proxies": {
    "http-proxy": "http://127.0.0.1:7890",
    "https-proxy": "http://127.0.0.1:7890",
    "no-proxy": "localhost"
  }
}

十、Docker Registry

Docker Registry 是官方提供的工具,用于构建私有镜像仓库。

(一)环境搭建

  1. 拉取镜像
docker pull registry
  1. 启动 Docker Registry
docker run -d -p 5000:5000 -v /home/hanwang/:/tmp/registry --privileged=true registry
  1. 验证(查看私服中的所有镜像)
curl -XGET http://192.168.30.134:5000/v2/_catalog

(二)向 Registry 私仓中上传镜像

  1. 配置 docker 允许接收 http 请求
    修改 /etc/docker/daemon.json,添加 insecure-registries 允许 http:
{
"insecure-registries": ["192.168.30.134:5000"]
}

然后重启 docker:

sudo systemctl daemon-reload
sudo systemctl restart docker
  1. 推送到私仓
docker tag hw_ubuntu:v2 192.168.30.134:5000/hw_ubuntu:v2
docker push 192.168.30.134:5000/hw_ubuntu:v2
  1. 查看私仓中镜像目录验证
curl -XGET http://192.168.30.134:5000/v2/_catalog
  1. 拉取验证
docker pull 192.168.30.134:5000/hw_ubuntu:v2

十一、容器卷的挂载

(一)容器挂载卷命令

docker run -ti --privileged=true -v /tmp/host_data:/tmp/docker_data --name=u1 ubuntu

(二)查看容器挂载卷

docker inspect 容器uuid

(三)数据共享

  1. dockers 修改,主机同步获得
  2. 主机修改,docker 同步获得
  3. docker 容器 stop,主机修改,docker 容器重启数据依旧同步

(四)容器卷的读写规则

容器和主机文件共享操作,默认权限为 rw:可读可写。可以修改 /容器目录:ro 镜像名 实现容器自己只能读取不能写的功能。

(五)容器卷的继承和共享

docker run -ti --privileged=true --volumes-from u1 --name=u2  ubuntu

继承卷的容器可以访问和修改卷中的数据。多个容器继承同一个卷时,它们之间可以实时共享数据。例如,一个容器修改了卷中的文件,其他继承该卷的容器也能立即看到这些更改。

十二、MySQL 安装

(一)简单版 Mysql

docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=12345 -d mysql

简单版的 Mysql 会存在以下问题:

  • 中文乱码
  • 没有容器卷映射

(二)实际应用版 Mysql 安装

docker run -p 3306:3306 -v /hwuse/mysql/log:/var/log/mysql -v /hwuse/mysql/data:/var/lib/mysql -v /hwuse/mysql/conf:/etc/mysql/conf.d --name mysql -e MYSQL_ROOT_PASSWORD=12345 -d mysql

/hwuse/mysql/conf 下新建 my.cnf,通过容器卷同步给 mysql 实例,解决中文乱码问题:

[client]
default-character-set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8

重启 mysql 容器,使得容器重新加载配置文件:

docker restart mysql

十三、Mysql 主从复制安装(使用mysql5.7)

(一)安装主服务器容器实例(端口号 3307)

  1. 启动容器实例
docker run -p 3307:3306 \
           --name mysql-master \
           --privileged=true \
           -v /app/mysql-master/log:/var/log/mysql \
           -v /app/mysql-master/data:/var/lib/mysql \
           -v /app/mysql-master/conf:/etc/mysql/conf.d \
           -e MYSQL_ROOT_PASSWORD=root \
           -d mysql:5.7
  1. 进入 /app/mysql-master/conf,新建 my.cnf 配置文件:
[mysqld]
server_id=101
binlog-ignore-db=mysql
log-bin=mall-mysql-bin
binlog_cache_size=1M
binlog_format=mixed
expire_logs_days=7
slave_skip_errors=1062
  1. 重启容器实例
docker restart mysql-master
  1. 进入容器实例内
docker exec -it mysql-master /bin/bash
  1. 登录 mysql,创建数据同步用户
create user 'slave'@'%' identified by '123456';
grant replication slave, replication client on *.* to 'slave'@'%';
flush privileges;

(二)安装从服务器容器实例(端口号 3308)

  1. 启动容器实例
docker run -p 3308:3306 \
           --name mysql-slave \
           --privileged=true \
           -v /app/mysql-slave/log:/var/log/mysql \
           -v /app/mysql-slave/data:/var/lib/mysql \
           -v /app/mysql-slave/conf:/etc/mysql/conf.d \
           -e MYSQL_ROOT_PASSWORD=root \
           -d mysql:5.7
  1. 进入 /app/mysql-slave/conf,新建 my.cnf 配置文件:
[mysqld]
server_id=102
binlog-ignore-db=mysql
log-bin=mall-mysql-slave1-bin
binlog_cache_size=1M
binlog_format=mixed
expire_logs_days=7
slave_skip_errors=1062
relay_log=mall-mysql-relay-bin
log_slave_updates=1
read_only=1
  1. 修改完配置需要重启 slave 容器实例
docker restart mysql-slave
  1. 在主数据库中查看主从同步状态
docker exec -it mysql-master /bin/bash
mysql -uroot -p
show master status;
  1. 进入从数据库容器,配置主从复制
docker exec -it mysql-slave /bin/bash
mysql -uroot -p
change master to master_host='192.168.30.134',master_user='slave',master_password='123456',master_port=3307,master_log_file='mall-mysql-bin.000001',master_log_pos=769,master_connect_retry=30;
  1. 查看主从同步状态
show slave status \G;
  1. 开启主从同步
start slave;

十四、Docker 安装 Redis

(一)单机版安装

1. 简单版 Redis

简单的启动 Redis 容器:

docker run -p 6379:6379 -d redis:6.0.8

2. 实际应用版 Redis

配置文件、数据文件都和容器卷进行映射。

  1. 宿主机创建目录 /app/redis
  2. /app/redis 下创建文件 redis.conf,主要修改以下几项配置:
requirepass 123
bind 127.0.0.1
protected-mode no
daemonize no
appendonly yes
  1. 启动 docker 容器:
docker run -d -p 6379:6379 --name redis --privileged=true \
-v /app/redis/redis.conf:/etc/redis/redis.conf \
-v /app/redis/data:/data \
-v /var/log/redis:/var/log/redis \
redis:6.0.8 sh -c "mkdir -p /var/lib/redis && redis-server /etc/redis/redis.conf"

十五、Redis 集群搭建

(一)集群存储算法

1. 哈希取余算法分区

算法描述:hash(key) % N(其中,key 是要存入 Redis 的键名,N 是 Redis 集群的机器台数)。用户每次读写操作,都是根据传入的键名经过哈希运算,对机器台数取余决定该键存储在哪台服务器上。

2. 一致性哈希算法分区

算法背景:一致性哈希算法是为了解决哈希取余算法中的分布式缓存数据变动和映射问题。当服务器个数发生变化时,尽量减少影响到客户端与服务器的映射关系。

3. 哈希槽算法分区

哈希槽实质上就是一个数组,数组 [0, 2^14 - 1] 形成的 hash slot 空间。目的是为了解决均匀分配的问题。在数据和节点之间又加入了一层,把这层称之为槽(slot),用于管理数据和节点之间的关系。

(二)Redis 集群存储策略

Redis 集群使用的就是哈希槽。Redis 集群有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置在哪个槽,集群的每个节点负责一部分 hash 槽。

(三)搭建 3 主 3 从 Redis 集群

  1. 启动 6 台 redis 容器
docker run -d --name redis-node-1 --net host --privileged=true -v /app/redis-cluster/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /app/redis-cluster/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /app/redis-cluster/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /app/redis-cluster/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /app/redis-cluster/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /app/redis-cluster/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
  1. 构建主从关系
docker exec -it redis-node-1 /bin/bash
redis-cli --cluster create 192.168.30.134:6381 192.168.30.134:6382 192.168.30.134:6383 192.168.30.134:6384 192.168.30.134:6385 192.168.30.134:6386 --cluster-replicas 1

十六、Dockerfile

Dockerfile 是用来构建 Docker 镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

(一)构建步骤

  1. 编写 Dockerfile 文件
  2. 使用 docker build 命令构建镜像
  3. 使用 docker run 依据镜像运行容器实例

(二)Dockerfile 保留字

  • FROM:基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板。Dockerfile 第一条必须是 FROM。
  • MAINTAINER:镜像维护者的姓名和邮箱地址。
  • RUN:容器构建时需要运行的命令。
  • EXPOSE:当前容器对外暴露出的端口。
  • WORKDIR:指定在创建容器后,终端默认登录进来的工作目录。
  • USER:指定该镜像以什么样的用户去执行,如果不指定,默认是 root。
  • ENV:用来在构建镜像过程中设置环境变量。
  • VOLUME:容器数据卷,用于数据保存和持久化工作。
  • ADD:将宿主机目录下(或远程文件)的文件拷贝进镜像,且会自动处理 URL 和解压 tar 压缩包。
  • COPY:类似 ADD,拷贝文件和目录到镜像中。
  • CMD:容器启动命令,指定容器启动后要干的事情。
  • ENTRYPOINT:用来指定一个容器启动时要运行的命令。

(三)构建镜像

创建名称为 Dockerfile 的文件,示例:

FROM ubuntu
MAINTAINER lee<lee@xxx.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN apt-get update
RUN apt-get install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "install ifconfig cmd into ubuntu success ....."
CMD /bin/bash

编写完成之后,将其构建成 docker 镜像。

docker build -t ubuntu:1.0.1 .

十七、构建一个简单的 Python 应用的镜像

(一)项目结构

my_python_app/
├── app.py
├── requirements.txt
└── Dockerfile

(二)文件内容

1. app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello from Dockerized Flask App!"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

2. requirements.txt

Flask==2.2.2
Werkzeug==2.2.2

3. Dockerfile

# 使用官方 Python 基础镜像
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 将依赖文件复制到容器中
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 将应用代码复制到容器中
COPY . .

# 暴露应用运行的端口
EXPOSE 5000

# 启动应用
CMD ["python", "app.py"]

(三)构建和运行 Docker 镜像

  1. 构建镜像
docker build -t my-python-app .
  1. 运行容器
docker run -d -p 5000:5000 --name my-python-container my-python-app
  1. 访问应用
    打开浏览器,访问 http://localhost:5000,你应该会看到页面显示:
Hello from Dockerized Flask App!

十八、虚悬镜像

虚悬镜像:仓库名、标签名都是 <none> 的镜像,称为 dangling images(虚悬镜像)。在构建或者删除镜像时可能由于一些错误导致出现虚悬镜像。

(一)列出 docker 中的虚悬镜像

docker image ls -f dangling=true

(二)删除虚悬镜像

docker image prune

十九、Docker 网络

(一)Docker 网络模式

  • bridge:为每一个容器分配、设置 IP 等,并将容器连接到一个 docker0 虚拟网桥,默认为该模式。
  • host:容器将不会虚拟出自己的网卡、配置自己的 IP 等,而是使用宿主机的 IP 和端口。
  • none:容器有独立的 Network namespace,但并没有对齐进行任何网络设置,如分配 veth pair 和 网桥连接、IP 等。
  • container:新创建的容器不会创建自己的网卡和配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。

(二)查看 Docker 网络模式

docker network ls

(三)添加 Docker 网络

docker network add xxx

(四)删除 Docker 网络

docker network rm xxx

(五)查看网络元数据

docker network inspect xxx

(六)删除所有无效的网络

docker network prune

(七)查看某个容器的网络模式

docker inspect 容器ID | tail -n 20

(八)docker0

Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为 docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。

(九)bridge 模式

Docker 使用 Linux 桥接,在宿主机虚拟一个 Docker 容器网桥(docker0),Docker 启动一个容器时会根据 Docker 网桥的网段分配给容器一个 IP 地址,称为 Container-IP,同时 Docker 网桥是每个容器的默认网关。因为在同一个宿主机内的容器接入同一个网桥,这样容器之间就能够通过容器的 Container-IP 直接通信。

(十)host 模式

直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行 NAT 转换。容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network space。容器将不会虚拟出自己的网卡,而是直接使用宿主机的 IP 和端口。

(十一)none 模式

禁用网络功能。在 none 模式下,并不为 docker 容器进行任何网络配置。进入容器内,使用 ip addr 查看网卡信息,只能看到 lo(本地回环网络 127.0.0.1 网卡)。

(十二)container 模式

新建的容器和已经存在的一个容器共享网络 IP 配置,而不是和宿主机共享。新创建的容器不会创建自己的网卡、IP,而是和一个指定的容器共享 IP、端口范围。两个容器除了网络共享,其他的如文件系统、进程列表依然是隔离的。

(十三)自定义网络

容器间的互联和通信以及端口映射。容器 IP 变动时候可以通过服务名直接网络通信而不受影响。

示例:

docker run --name mysql-matomo -p 3308:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.28
docker run -d -p 8888:80 --link mysql-matomo:db --name matomo matomo:4.9.0

二十、Docker-compose

Docker-Compose 是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。

(一)核心概念

  • 服务(service):一个个应用容器实例
  • 工程(project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 中定义

(二)Compose 使用的三个步骤

  1. 编写 Dockerfile 定义各个应用容器,并构建出对应的镜像文件
  2. 编写 docker-compose.yml,定义一个完整的业务单元,安排好整体应用中的各个容器服务
  3. 执行 docker-compose up 命令,其创建并运行整个应用程序,完成一键部署上线

(三)安装 Docker-Compose

curl -L https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose version

(四)常用命令

  • 查看帮助
docker-compose -h
  • 创建并启动 docker-compose 服务
docker-compose up
docker-compose up -d
  • 停止并删除容器、网络、卷、镜像
docker-compose down
  • 进入容器实例内部
docker-compose exec <yml里面的服务id> /bin/bash
  • 展示当前 docker-compose 编排过的运行的所有容器
docker-compose ps
  • 展示当前 docker-compose 编排过的容器进程
docker-compose top
  • 查看容器输出日志
docker-compose log <yml里面的服务id>
  • 检查配置
docker-compose config
docker-compose config -q
  • 重启服务
docker-compose restart
  • 启动服务
docker-compose start
  • 停止服务
docker-compose stop

(五)compose 编排实例

1. 项目结构

my_blog/
├── app/
│   ├── main.py
│   ├── requirements.txt
│   └── Dockerfile
├── db/
│   └── init.sql
├── docker-compose.yml

2. 文件内容

(1)main.py
from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def home():
    return "Hello, this is my blog!"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
(2)requirements.txt
Flask==2.2.2
Werkzeug==2.2.2
(3)Dockerfile
# 使用 Python 官方镜像作为基础镜像
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 复制当前目录下的所有文件到容器的工作目录
COPY . .

# 安装依赖
RUN pip install -r requirements.txt

# 暴露端口
EXPOSE 5000

# 启动应用
CMD ["python", "main.py"]
(4)init.sql
CREATE DATABASE blog;
USE blog;

CREATE TABLE posts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL
);
(5)docker-compose.yml
version: '3.3'

services:
  web:
    build: ./app
    ports:
      - "5000:5000"
    depends_on:
      - db
    environment:
      - DB_HOST=db
      - DB_NAME=blog
      - DB_USER=root
      - DB_PASSWORD=secret

  db:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_DATABASE=blog
    volumes:
      - db_data:/var/lib/mysql
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "3306:3306"

volumes:
  db_data:

(六)构建和运行

在项目根目录下运行以下命令来构建和启动服务:

docker-compose up --build

(七)验证

  • 打开浏览器访问 http://localhost:5000,你应该能看到 "Hello, this is my blog!" 的消息。
  • 数据库服务会自动初始化,并创建一个名为 blog 的数据库和一个 posts 表。

(八)停止和清理

当你完成测试后,可以通过以下命令停止并清理服务:

docker-compose down
posted @ 2025-06-21 23:46  harrylearn66666  阅读(10)  评论(0)    收藏  举报