Docker技术学习指南:从入门到实践

引言

Docker是一款开源的应用容器引擎,起源于2013年,基于Go语言开发,并遵循Apache 2.0协议进行开源发布。它的出现是为了解决软件交付过程中的“环境一致性”问题,通过将应用及其依赖打包成可移植、轻量级的容器(Container),确保应用在任何地方运行都能得到一致的行为和性能。

一、Docker基础概念与安装:

Docker基础概念

1.镜像(Image)   

  • 镜像是Docker容器的构建块,它是只读的模板,包含了运行一个应用所需的全部内容:代码、依赖库、环境变量等。创建镜像通常通过编写Dockerfile并使用docker build命令完成。
   # Dockerfile示例
   FROM ubuntu:latest
   RUN apt-get update && apt-get install -y curl
   CMD ["curl", "http://example.com"]
   
  • 构建镜像:
     docker build -t my-ubuntu-curl .
     

2.容器(Container):

  • 容器是从镜像启动的可执行实例,每个容器都有自己的文件系统、网络空间和进程隔离。容器是轻量级的虚拟化解决方案,共享主机内核,但拥有独立视图。
  • 运行容器:
     docker run -it --name my-running-container my-ubuntu-curl
     

3.仓库(Registry):

  • 仓库用于存储和分发Docker镜像,Docker Hub是最常用的公共仓库,用户也可以搭建私有仓库如Harbor。
  • 拉取镜像:
     docker pull nginx
     
  • 推送镜像到仓库:
     docker tag nginx:latest yourusername/nginx:custom-tag
     docker push yourusername/nginx:custom-tag
     

Docker安装步骤(以Ubuntu为例)

1. 更新包索引:

sudo apt-get update

2. 安装必要的一些系统工具:

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

3. 添加Docker的GPG密钥:

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

4. 设置稳定版Docker仓库源: 

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

5. 更新包索引并安装Docker Engine:

sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io

6. 启动并设置开机自启Docker服务:

sudo systemctl start docker sudo systemctl enable docker

7. 验证Docker是否安装成功:

docker --version

8. (可选)非root用户使用Docker,需要添加用户到docker组:

sudo usermod -aG docker $USER

以上就是Docker的基础概念及其在Ubuntu上的安装过程,不同操作系统可能安装方法略有差异,请根据实际操作系统的官方文档进行安装。

二、Docker数据管理

在Docker中,数据管理主要包括容器内部数据的持久化和多容器间数据共享。为了确保容器停止或重启后数据不丢失,以及多个容器之间能够共享数据,Docker提供了两种主要的数据持久化方法:数据卷(Data Volumes)和数据卷容器(Data Volume Containers)。

1. 数据卷(Data Volumes)

数据卷是宿主机上的一个目录或者文件,它可以被挂载到容器内部的一个指定路径上,使得容器内部对这个目录或文件的操作能够持久保存,并且可以跨容器共享。

  • 创建并使用数据卷:
   # 创建一个新的容器时同时挂载数据卷
   docker run -d --name web_server -v /var/www/html:/app/data nginx

   # 其中:
   # `-v` 参数用于创建或挂载数据卷,格式为 `:`
   # `/var/www/html` 是宿主机上的目录
   # `/app/data` 是容器内的目录
   

  • 查看数据卷:
   docker volume ls
   

  • 直接创建数据卷(不挂载至容器):
   docker volume create my_data_volume
   

  • 将已存在的数据卷挂载到新的容器:
   docker run -d --name another_web_server -v my_data_volume:/app/data nginx
   

2. 数据卷容器(Data Volume Containers)

数据卷容器其实是一个专门用来存储数据的容器,它本身可能并不运行任何服务,但其内部的数据卷可供其他容器挂载使用。

  • 创建数据卷容器
   docker run -d --name data_container -v /data busybox true
   

  • 将数据卷容器中的数据卷挂载到其他容器:
   docker run -d --name web_server --volumes-from data_container -w /data nginx
   

这里,--volumes-from 参数表示从名为 data_container 的容器中挂载数据卷到当前容器内。

3. 挂载主机目录作为数据卷

如果需要容器修改宿主机上的某个目录内容,并希望这些改动持久化:

docker run -d -v /your/host/path:/container/path your_image

这样做的好处是可以直接访问和修改宿主机上的文件,便于本地开发环境与容器进行交互。
总结来说,通过合理地管理和使用数据卷,用户可以灵活处理容器内外部的数据持久化问题,确保应用在容器间的迁移和扩展过程中数据的一致性和完整性。

三、Docker网络配置


Docker提供了几种不同的网络模式来满足容器间以及容器与宿主机、外部网络之间的通信需求。主要的网络模式包括:

1.Bridge(桥接)网络

  • 默认网络模式,每个新创建的容器都会自动加入到一个名为bridge的网络中。
  • 示例:
     # 创建一个新的容器并连接到默认桥接网络
     docker run -itd --name my_container nginx

     # 查看网络详细信息
     docker network inspect bridge
     

2.Host(主机)网络

  • 容器共享宿主机的网络栈,直接使用宿主机的IP地址和端口。
  • 示例:
     # 使用host网络模式运行容器
     docker run -itd --network host --name my_host_container nginx
     

3.None(无网络)

  • 容器没有网络接口,通常用于安全测试或者不需要网络连接的场景。
     # 使用none网络模式运行容器
     docker run -itd --network none --name my_none_container nginx
     

4.自定义网络

  • 用户可以创建自己的网络,实现容器间的隔离或互联。
  • 创建自定义桥接网络
     docker network create --driver bridge custom_network
     
  • 将容器连接到自定义网络:
     # 创建并连接到自定义网络
     docker run -itd --network custom_network --name container1 nginx
     docker run -itd --network custom_network --name container2 alpine ash

     # 在同一自定义网络内的容器可以直接通过容器名通信
     docker exec container1 ping container2
     

5.Overlay网络(集群网络)

  • 用于跨多主机节点的容器间通信,常在Docker Swarm等集群环境中使用。
  • 创建overlay网络(需要在Swarm模式下):
     docker network create --driver overlay --attachable my_overlay_net
     
  • 连接容器到overlay网络:
     docker service create --name my_service --network my_overlay_net image_name
     

每种网络模式都有其特定的应用场景和用途,在实际部署和运维过程中,应根据具体需求灵活选择合适的网络策略

四、Docker安全性和隔离性

Docker通过多种方式提供安全性保障和资源隔离,以下是一些关键的安全配置示例和详细讲解:

1. 用户权限管理

  • 默认情况下,容器内的进程以root权限运行。为了增强安全性,可以创建非root用户并在容器中使用该用户运行应用。

代码示例:

在Dockerfile中创建新用户并指定其运行程序:

# 创建一个名为appuser的用户,并将其uid和gid设为1000(可根据实际需求调整)
RUN groupadd -g 1000 appuser && useradd -u 1000 -g appuser appuser

# 设置工作目录并确保所有权归appuser所有
WORKDIR /app
RUN chown -R appuser:appuser /app

# 使用非root用户运行应用程序
USER appuser

# 复制应用程序文件到容器内
COPY . /app

# 执行应用程序
CMD ["./your_app"]

2. 限制容器特权

  • 避免给容器过多不必要的权限,可以通过--privileged标志控制容器是否拥有主机的所有能力。

不启用特权模式启动容器:

docker run --rm -it --name my_container --user appuser --cap-drop ALL image_name

这里,--cap-drop ALL表示移除所有Linux能力(capabilities),只允许基础功能。同时结合非root用户使用,降低容器内部操作对宿主机的影响。

3. 网络隔离

  • Docker提供了不同的网络驱动,如桥接、主机、none等来实现网络层面的隔离。
  • 创建独立的桥接网络供特定容器使用,提高网络安全性:
docker network create --driver bridge isolated_network

docker run --rm -d --net=isolated_network --name container1 image1

4. 存储卷访问权限

  • 控制容器对宿主机存储卷的访问权限,防止不当的数据暴露。
  • 可以在挂载卷时指定容器内的文件权限:
docker run -v /host/path:/container/path:ro --name container2 image2

这里的:ro表示容器内挂载点为只读,避免容器修改宿主机数据。

5. 运行时安全选项

  • 使用seccomp profile来限制容器可执行的系统调用。
  • 在容器启动时设置seccomp规则:
docker run --security-opt seccomp=path/to/seccomp/profile.json your_image

其中,path/to/seccomp/profile.json是自定义的seccomp过滤规则文件。

综上所述,Docker通过用户权限管理、权限削减、网络隔离以及运行时安全选项等多种手段来强化容器的安全性和隔离性。用户在实际部署过程中应根据业务需求灵活应用这些策略,以最大程度地保证系统的安全稳定。

五、Docker Compose

Docker Compose是一个用于定义和运行多容器Docker应用的工具,它允许用户通过一个YAML文件(通常命名为docker-compose.yml)来配置应用程序的服务、网络以及数据卷等组件,并且可以使用一条命令完成多个服务的构建、启动、停止及重启等操作。

Docker Compose基本结构与代码示例


以下是一个简单的docker-compose.yml文件示例,该文件描述了一个包含web服务器(基于Nginx镜像)和后端API服务(基于Python Flask框架)的多容器应用:

version: '3.9' # 指定Compose文件格式版本

services:
  web:
    image: nginx:latest
    ports:
      - "80:80" # 将容器的80端口映射到主机的80端口
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf # 挂载本地的nginx配置文件到容器内
    depends_on: # 表明web服务依赖于api服务
      - api

  api:
    build: . # 使用当前目录下的Dockerfile构建镜像
    command: python app.py # 启动时执行的命令
    environment: # 设置环境变量
      FLASK_ENV: development
      SECRET_KEY: mysecretkey
    volumes:
      - .:/app # 将项目源码挂载到容器内的/app目录下,便于开发调试
      - ./data:/app/data # 数据持久化目录
    ports:
      - "5000:5000" # 映射容器内部的5000端口到主机的5000端口

networks:
  default: # 默认网络,所有服务都会连接到这个网络中
    name: my_app_net

使用Docker Compose命令操作示例

  • 启动项目:
docker-compose up -d # `-d`表示在后台运行

  • 停止并移除所有容器、网络、卷等资源:
docker-compose down

  • 重新构建并启动服务:
docker-compose up --build -d

  • 查看服务状态:
docker-compose ps

  • 进入正在运行的容器交互式shell:
docker-compose exec web bash # 进入名为web的服务容器

通过Docker Compose,开发者可以更方便地组织和管理多容器应用,简化了部署流程,提高了协作效率。同时,其支持的网络、数据卷等特性能够更好地模拟真实生产环境中的部署架构。

六、Docker Swarm 或 Kubernetes(可选)

1.Docker Swarm

Docker Swarm 是 Docker 官方提供的容器编排工具,它允许用户在一组主机上创建和管理一个Docker集群。Swarm使用原生的Docker API和CLI命令来部署和管理容器化应用。

创建Docker Swarm集群(初始化主节点)

# 在一台机器上初始化Swarm作为管理节点
docker swarm init [--advertise-addr ]

# 输出将包含加入集群的worker节点命令

例如:

docker swarm init --advertise-addr 192.168.1.100

将工作节点加入到Swarm集群中

# 在其他机器上执行以下命令以加入到已初始化的Swarm集群
docker swarm join --token  :

创建并部署服务(Stack)

在docker-compose.yml文件中定义服务和网络等资源:

version: '3.9'

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    deploy:
      replicas: 3 # 部署三个副本
      restart_policy:
        condition: on-failure

networks:
  default:
    driver: overlay # 使用overlay网络跨越多个节点

然后,使用docker stack deploy命令部署Stack:

docker stack deploy -c docker-compose.yml my_stack

2.Kubernetes (K8s)

Kubernetes 是一个开源的、可移植的、可扩展的平台,用于自动化容器化应用程序的部署、扩展和管理。与Docker Swarm类似,它提供了一种管理和运行容器化应用的方式。

创建最小化的Kubernetes集群(使用minikube)

安装minikube后,启动一个单节点集群:

minikube start

应用部署示例(Deployment)

首先编写一个名为nginx-deployment.yaml的Kubernetes Deployment配置文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

然后创建并部署这个Deployment:

kubectl apply -f nginx-deployment.yaml

以上代码示例分别展示了如何在Docker Swarm和Kubernetes中创建和部署简单的Nginx服务。两者都支持水平伸缩、滚动更新、健康检查等功能,但Kubernetes提供了更丰富的高级特性,如自愈能力、自动调度、Service发现机制以及复杂的网络策略等。

七、Docker私有Registry搭建

搭建一个Docker私有Registry非常简单,你可以使用官方提供的registry镜像来快速创建并运行。以下是具体的步骤:

1. 拉取最新版本的Docker Registry镜像

docker pull registry:2 # 拉取最新版的registry v2版本镜像

2. 运行私有Registry容器

  • 基本启动命令:
  docker run -d -p 5000:5000 --restart=always --name my-registry registry:2
  
  • -d:表示以守护进程模式运行容器。
  • -p 5000:5000:将宿主机的5000端口映射到容器内的5000端口,这是Registry服务监听的端口。
  • --restart=always:确保在宿主机重启后,Registry容器能够自动启动。
  • --name my-registry:为容器指定一个名称。
  • registry:2:是运行的镜像名。
  • 防火墙设置: 如果你的系统开启了防火墙(如iptables或firewalld),需要开放5000端口供外部访问,或者临时关闭防火墙以便测试:
   # 对于 firewalld
   systemctl stop firewalld.service     # 停止防火墙
   systemctl disable firewalld.service  # 禁止防火墙开机启动 (仅限生产环境确认安全策略后操作)
   firewall-cmd --permanent --add-port=5000/tcp # 或者只打开5000端口(推荐)

   # 对于 iptables
   iptables -A INPUT -p tcp --dport 5000 -j ACCEPT
   service iptables save
   

3. 配置客户端信任私有Registry
为了能够在Docker客户端中推拉镜像,需要配置Docker daemon信任这个私有Registry服务器。在 /etc/docker/daemon.json 文件中添加如下内容(如果文件不存在则创建):

{
  "insecure-registries": ["your.registry.host:5000"]
}

这里的 your.registry.host 应替换为你的私有Registry服务所在的主机IP地址或域名。
然后重启Docker服务使配置生效:

systemctl restart docker

4. 使用私有Registry

  • 推送镜像:

        首先给镜像打上指向私有Registry的标签,并推送到Registry:

   docker tag nginx:latest your.registry.host:5000/nginx:latest
   docker push your.registry.host:5000/nginx:latest
   
  • 从私有Registry拉取镜像:
   docker pull your.registry.host:5000/nginx:latest
   

以上即是在Linux环境中搭建和使用私有Docker Registry的基本过程。对于更复杂的部署场景,你可能需要考虑认证、加密传输以及与Harbor等可视化管理工具集成等问题。

八、Docker与持续集成/持续部署(CI/CD)

Docker与持续集成/持续部署(CI/CD)结合,使得开发团队能够自动化构建、测试和部署应用程序。以下是一个基于GitLab CI/CD的示例,它使用Docker来构建镜像,并将其推送到私有Registry,然后在目标环境中拉取并运行新镜像以实现自动部署。

1. 创建Dockerfile

在项目根目录下创建一个Dockerfile,用于定义如何构建应用的容器镜像:

# Dockerfile
FROM python:3.9

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app.py"]

2. 配置.gitlab-ci.yml

在项目的根目录下创建.gitlab-ci.yml文件,这是GitLab CI/CD配置文件:

# .gitlab-ci.yml
image: docker:latest # 使用Docker作为CI环境的基础镜像

services:
  - docker:dind # 在CI环境下启用Docker服务

stages:
  - build
  - deploy

variables:
  REGISTRY_URL: registry.example.com
  IMAGE_TAG: $CI_COMMIT_SHA

build-image:
  stage: build
  script:
    - docker login -u "$REGISTRY_USER" -p "$REGISTRY_PASSWORD" $REGISTRY_URL
    - docker build -t $REGISTRY_URL/my-app:$IMAGE_TAG .
    - docker push $REGISTRY_URL/my-app:$IMAGE_TAG
  only:
    - branches # 只针对分支触发该阶段

deploy-to-production:
  stage: deploy
  script:
    - ssh my_production_server 'docker pull $REGISTRY_URL/my-app:$IMAGE_TAG && docker stop my_app_container || true && docker rm my_app_container || true && docker run -d --name my_app_container -p 80:5000 $REGISTRY_URL/my-app:$IMAGE_TAG'
  environment:
    name: production
    url: https://my-production-app.example.com
  when: manual # 手动触发生产环境部署
  only:
    - master # 只针对master分支触发该阶段

详细讲解:

  • .gitlab-ci.yml中定义了两个阶段:build和deploy。
  • build-image阶段会登录私有Registry,构建包含应用代码的新Docker镜像,并将其推送到Registry。
  • deploy-to-production阶段则通过SSH连接到生产服务器上,从Registry拉取最新的镜像,停止并删除旧的容器实例(如果存在),然后启动新的容器实例。
  • 这里假设你已经设置了环境变量REGISTRY_USER、REGISTRY_PASSWORD以便于在CI流程中登录Registry。
  • when: manual意味着生产环境部署需要手动触发,确保只有在确认无误的情况下才会执行

这个示例展示了如何将Docker和GitLab CI/CD结合,实现了一个简单的CI/CD流水线,可以扩展此模板以满足更复杂的应用场景,比如添加更多测试阶段、验证环节等。

总结

通过深入理解和熟练掌握上述内容,你将能够充分运用Docker技术来优化你的软件开发流程、提升部署效率,并确保应用在不同环境下的稳定运行。随着持续的技术迭代和社区支持,Docker作为云原生计算的重要基石,在现代IT架构中发挥着不可替代的作用。

你可能感兴趣的:(docker,容器,运维)