【程序员必备】Docker学习笔记

144 阅读14分钟

Docker

笔记基于视频:尚硅谷 3 小时速通 Docker 教程,名师带练 docker 部署到实战!

一、Docker 介绍

1.架构介绍

Docker 是一种容器化技术。

它类似于虚拟机,可以在里面运行程序。

只不过 Docker 使用的系统是最小的 Linux 内核。

相对于 Windows 虚拟机,Docker 占用的资源更少。

Docker 里面有两个重要的概念:镜像(Images)、容器(Containers)。

镜像可以理解成一个自定义的 Windows 的 ISO 文件,里面安装了需要运行的程序,它可以随便分享给任何人,人们安装到电脑上就可以启动系统。

容器就是运行的虚拟机,简单来说就是镜像(Images)安装到电脑上运行起来。一台电脑可以同时运行多个虚拟机,同理一个电脑上也可以运行多个容器。

每个容器拥有自己的系统,容器之间相互隔离,但是可以通信。

为了方便人们分享自己的容器,Docker 提供了一个镜像市场 DockerHub。

为了方便操作镜像和容器 Docker 开发了一套命令 Docker-cli。

image

2.Docker 安装

  1. 准备 Linux 环境

  2. 如果已经安装过需要卸载旧版 Docker 环境

    yum remove docker \
        docker-client \
        docker-client-latest \
        docker-common \
        docker-latest \
        docker-latest-logrotate \
        docker-logrotate \
        docker-engine
    
  3. 配置 yum 源

    # 第一步:安装yum-utils工具
    yum install -y yum-utils
    
    # 第二步:配置Docker的yum源
    yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    
  4. 安装 Docker

    yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    
  5. 启动和校验

    # 查看docker版本
    docker -v
    
    # 启动Docker
    systemctl start docker
    
    # 查看docker进程是否正常启动
    docker images
    
    # 停止Docker
    systemctl stop docker
    
    # 重启
    systemctl restart docker
    
    # 设置开机自启
    systemctl enable docker
    
    # 执行docker ps命令,如果不报错,说明安装启动成功
    docker ps
    

3.配置镜像加速

#第一步:
sudo mkdir -p /etc/docker
#第二步:
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["加速器地址"]
}
EOF
#第三步:
sudo systemctl daemon-reload
#第四步:
sudo systemctl restart docker

二、Docker 命令

1.基本命令

说明:[] ​中的内容表示可选操作

类型操作命令说明案例
镜像操作
查找镜像docker search#查找 nginx 镜像
docker search nginx
下载镜像docker pull 镜像名[:版本号]版本号可以省略,不加版本号默认下载最新的镜像#下载 nginx 镜像
docker pull nginx
docker pull nginx:1.26.0
查看本地下载的镜像docker images#查看当前系统下载的镜像
docker images
删除本地下载的镜像docker rmi可以通镜像名删除,也可以通过镜像 id 删除#删除刚下载的镜像
docker rmi nginx:1.26.0
查看镜像详情docker image inspect#查看刚刚下载的镜像详情
docker image inspect myimage
容器操作运行容器docker run其他参数要写到 run 和镜像名的中间#创建并运行 nginx 容器
docker run [其他参数] nginx
查看运行中的容器docker ps [-a]-a 参数:可以查看所有容器,包括停止的#查看启动中的容器信息
docker ps
停止容器docker stop#停止 nginx
docker stop nginx
启动容器docker start可以启动停止的容器#启动 nginx
docker start nginx
重启容器docker restart#重启 nginx
docker restart nginx
查看容器状态docker stats#查看 nginx 容器的占用信息
docker stats nginx
查看容器日志docker logs#查看 nginx 容器的运行日志
docker logs nginx
进入容器内部docker exec-it 参数:以交互模式进入#以交互模式进入 nginx 容器
docker exec -it nginx bash
删除容器docker rm-f 参数:强制删除#删除 nginx 容器
docker rm nginx
查看容器信息docker inspect #4.查看容器基本信息
docker inspect 容器名
镜像打包提交镜像docker commit在容器当前状态下创建一个新镜像#将修改的 nginx 容器打包成一个新的镜像
docker commit -m "描述内容" 容器名 自定义镜像名:自定义版本号
​#保存镜像#​docker save将文件导出为本地文件(-o 参数:将文件打包成 tar 包)#将镜像打包成 tar 包
docker save -o 自定义文件名.tar 镜像名
​#加载镜像#​docker load将别人打的压缩包加载成镜像#将刚才打成的 tar 包加载为本地镜像
docker load -i 自定义文件名.tar
镜像发布
登录社区docker login
镜像命名docker tagdockerhub 的镜像都是用户名/镜像名因此要符合规则#给镜像命名
docker tag 镜像名[:版本号] 用户名/新镜像名[:版本号]
推送docker push#将镜像推送上去
docker push 用户名/新镜像名[:版本号]

2.run 命令详解

#1.基本用法 说明:[]中的内容可以省略
docker run [参数] 容器名[:版本号]

#2.参数详解
	-d :后台运行
	--name :给容器命名
	-p :端口映射(本机端口:容器端口)
	--restart always :开机启动
	-e :设置环境变量
	-v :目录挂载/数据卷挂载
	--network :指定网络

#完整案例:启动最新的nginx镜像,将本机的1188端口映射到宿主机的88端口
	docker run
			-d
			--name myNginx
			-p 1188:80
			nginx

三、Doceker 存储

Docker 容器与本机文件的交互方式有两种:

  1. 卷映射:容器中的文件映射到本机
  2. 目录挂载:本机文件或目录映射到容器内

卷映射与目录挂载在使用中的区别:

  1. 使用目录挂载的时候本地目录以 ./ ​或 / ​开始。使用卷映射的时候不以 ./ ​或 / ​开始。
  2. 数据卷仅可以在使用 docker run ​的时候挂载

总结:目录挂载更方便

1. 目录挂载

将本地文件或目录映射到容器内部,本地目录中的内容修改,容器中会同步修改

注意事项:

  1. 目录挂载必须要以 ./​ 或 /​ 开始开头,否则会被认为成数据卷挂载
  2. 目录挂载命令只能在创建容器时执行,如果容器已经创建了,就没法挂载了
#作用:将本地目录映射到容器内某个目录
-v 本地目录:容器内目录

#案例:将本地/app/nghtml目录映射到容器中的/usr/share/nginx/html中
docker run
		-d
		-v /app/nghtml:/usr/share/nginx/html
		-p 80:80
		--name myNgin
		nginx

2.卷映射

将容器中的文件映射到本机,本机修改文件,容器中的文件会同步修改。

映射卷挂载后默认存放在本机 /var/lib/docker/volumes/<自定义卷名> ​下(windows 存放到哪里自己查)

注意事项:

  1. 挂载数据卷命令只能在创建容器时执行,如果容器已经创建了,就没法挂载了
  2. 数据卷名字随便起
  3. 如果挂载的时候数据卷不存在,则会自动创建
  4. 直接删除容器,数据卷和里面的数据依旧会存在
#作用:将容器中的目录映射到本地
-v 自定义卷名:容器内的目录

#案例:将容器中的/etc/nginx映射到ngconf卷中
#(挂载完成后到本机的/var/lib/docker/volumes/<自定义卷名>下查看)
docker run
		-d
		-v nginx:/etc/nginx
		-p 80:80
		--name myNgin
		nginx

#补充:
#1.查看所有的卷
docker volume ls
#2.创建卷
docker volume create 卷名
#3.查看卷的信息
docker volume inspect 卷名

3.头脑风暴

问:如果一个容器已经使用 docker run ​运行了,我该怎么挂载卷或进行目录映射?

1.停止容器:docker stop my-container
2.提交容器状态docker commit my-container my-new-image
3.使用 docker run 重新启动提交的容器,并额外添加你需要的 -v 或 --mount 参数来指定新的卷或绑定挂载。
4.删除旧的容器(如果不需要了)

四、Docker 网络

Docker 网路主要介绍:Docker 容器之间如何相互通信

Docker 默认网络机制:所有的容器都会加入 docker0 ​网络,并分配一个唯一 ip 地址,因此他们可以通过容器内的 ip 互相访问。但是 docker 0 ​网络有一个缺点,不支持主机域名,只支持 ip 访问。而我们自己创建的 docker 网络可以通过主机域名访问,域名默认是容器的名字。因此我们可以通过创建自定义网络,实现容器之间通过容器名访问。

#常用命令
#1.创建网络
	docker network create 网络名
#2.列举网络
	docker network ls
#3.容器启动时加入指定网络
	--network 创建的自定义网络名
#4.查看容器基本信息
	docker inspect 容器名

#案例:创建一个网络,让两个容器都加入网络,并互相访问
#1.查看所有网络
docker network ls
#2.创建网络(后面的网络名随便起)
docker network create junqing
#3.容器加入
docker network connect junqing mysql
#4.新建容器,要求直接加入junqing网络
docker run -d --name junqing-oa -p 8080:8080 --network junqing oa
docker run -d --name mysql -p 3306:3306 --network junqing mysql
#5.进入mysql容器,通过容器名访问oa容器
curl http://oa:8080

五、环境变量

容器启动时需要指定的参数,通常镜像仓库的文档中会给出

#语法:-e key=value
#说明:一个-e只能指定一个环境变量,如果需要指定多个环境变量可以设置多个-e

#案例:
docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123 \
  mysql

六、Docker Compose

前面启动容器的时候都是一个一个启动,可是我们上线项目的时候需要上线十几个服务,一个一个启动太慢了。为了解决这个问题,可以使用 Docker Compose,编写好启动信息,到时候无论在任何环境都能快速启动文件内的所有容器

1.常用命令

#上线(指第一次启动)
#说明:[]中的内容可以省略,默认启动当前目录下的compose.yaml文件
docker compose [-f yaml文件] up -d
#下线
docker compose [-f yaml文件] down [其他参数]

#启动(非第一次启动)
docker compose start x1 x2 x3
#停止
docker compose stop x1 x2 x3
#扩容(让某个容器多启动几个)
docker compose scale x1 x2 x3

2.Compose文件

Compose文件是yaml​格式的,在书写的时候需要定义几种常用的属性:

  1. name​:应用名(给本次启动起一个名字)
  2. services​:服务配置(可以是多个服务,如:MySQL、Nginx)
  3. networks​ ​网络
  4. volumes​:卷映射(卷映射需要单独声明、目录挂载不需要单独声明)
  5. configs​ ​配置
  6. secrets​ 密钥

3.案例

#案例:使用compose启动多个容器,服务包括mysql、wordpress

#第一步:编辑Compose文件
#给本次启动起一个名字
name: myblog

#需要启动的服务及其配置
services:
 #mysql服务相关配置
 mysql:
  #容器名
  container_name: mysql
  #镜像
  image: mysql:8.0
  #端口
  ports:
   - 3306:3306
  #环境变量[数组写法一]
  environment:
   - MYSQL_ROOT_PASSWORD=123456
   - MYSQL_DATABASE=wordpress
  #数据卷
  volumes:
   - mysql-data:/var/lib/mysql
   - /app/myconf:/etc/mysql/conf.d
  #启动策略
  restart: always
  networks:
   - blog

 #wordpress服务相关配置
 wordpress:
  #容器名
  container_name: wordpress
  #镜像
  image: wordpress
  #端口
  ports:
   - 8080:80
  #环境变量[数组写法二]
  environment:
    WORDPRESS_DB_HOST: mysql
    WORDPRESS_DB_USER: root
    WORDPRESS_DB_PASSWORD: 123456
    WORDPRESS_DB_NAME: wordpress
  #数据卷
  volumes:
   - wordpress:/var/www/html
  #启动策略
  restart: always
  networks:
   - blog
   #配置启动顺序(wordpress在mysql之后启动)
  depends_on:
   - mysql

#卷映射
volumes:
 mysql-data:
 wordpress:

#网络
networks:
 blog:


#第二步:使用Compose启动容器
#中括号中的内容可以不写
docker compose [-f compose文件名] up -d

#第三步:我修改了部分配置内容,容器该怎么更新?只需要重新启动即可,只会变更修改的部分
#中括号中的内容可以不写
docker compose [-f compose文件名] up -d

#第四步:这个服务我不想用了怎么删除
#中括号中的内容意思是删除容器、网络、卷映射,不写默认不删除
docker compose [-f compose文件名] down [--rmi all -v]

七、DockerFile

我们自己写了一个项目,该怎么打包成镜像呢?这就用到了 DockerFile

1.常见参数

image

2.DockerFile

常用参数:

  1. FROM​:基础环境【可以是系统,如:centos。也可以是运行项目的版本,如:openjdk:17】
  2. LABEL​:标签【相当于说明,随便写就行】
  3. COPY​:将文件复制到镜像系统中
  4. ENTRYPOINT​:指定启动命令
  5. EXPOSE:暴露哪个端口

3.案例

#第一步:编辑Dockerfile文件
#基础运行环境 jdk8
FROM openjdk:8

#标签
LABEL 作者=123456

#复制文件到镜像 这里是将本地的app.jar复制到镜像系统根目录的app.jar中
COPY app.jar /app.jar

#指定启动命令
ENTRYPOINT java -jar /app.jar

#暴漏端口
EXPOSE 8080

#第二步:构建镜像【说明:最后一个点说明是在当前目录构建,非常重要】
#命令格式:docker build -f Dockerfile文件路径 -t 镜像名:版本号 .
docker build -f Dockerfile -t myimage:v1.0

#第三步:正常运行容器即可

八、Docker 综合案例

一键启动大型项目

  1. 由于有openserach因此需要提前操作一些命令

    sudo swapoff -a
    
    
    sudo vi /etc/sysctl.conf
    
    vm.max_map_count=262144
    
    sudo sysctl -p
    
    cat /proc/sys/vm/max_map_count
    
  2. 创建docker compose文件

    注意:需要修改kafuka中的ip配置,改成自己服务器的IP

    name: devsoft
    
    services:
      redis:
        image: bitnami/redis:latest
        restart: always
        container_name: redis
        environment:
          - REDIS_PASSWORD=123456
        ports:
          - '6379:6379'
        volumes:
          - redis-data:/bitnami/redis/data
          - redis-conf:/opt/bitnami/redis/mounted-etc
    
      mysql:
        image: mysql:8.0.31
        restart: always
        container_name: mysql
        environment:
          - MYSQL_ROOT_PASSWORD=123456
        ports:
          - '3306:3306'
          - '33060:33060'
        volumes:
          - mysql-conf:/etc/mysql/conf.d
          - mysql-data:/var/lib/mysql
    
      rabbit:
        image: rabbitmq:3-management
        restart: always
        container_name: rabbitmq
        ports:
          - "5672:5672"
          - "15672:15672"
        environment:
          - RABBITMQ_DEFAULT_USER=rabbit
          - RABBITMQ_DEFAULT_PASS=rabbit
          - RABBITMQ_DEFAULT_VHOST=dev
        volumes:
          - rabbit-data:/var/lib/rabbitmq
          - rabbit-app:/etc/rabbitmq
    
      opensearch-node1:
        image: opensearchproject/opensearch:2.13.0
        container_name: opensearch-node1
        environment:
          - cluster.name=opensearch-cluster
          - node.name=opensearch-node1
          - discovery.seed_hosts=opensearch-node1,opensearch-node2
          - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2
          - bootstrap.memory_lock=true
          - OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m
          - DISABLE_INSTALL_DEMO_CONFIG=true
          - DISABLE_SECURITY_PLUGIN=true
        ulimits:
          memlock:
            soft: -1
            hard: -1
          nofile:
            soft: 65536
            hard: 65536
        volumes:
          - opensearch-data1:/usr/share/opensearch/data
        ports:
          - 9200:9200
          - 9600:9600
    
      opensearch-node2:
        image: opensearchproject/opensearch:2.13.0
        container_name: opensearch-node2
        environment:
          - cluster.name=opensearch-cluster
          - node.name=opensearch-node2
          - discovery.seed_hosts=opensearch-node1,opensearch-node2
          - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2
          - bootstrap.memory_lock=true
          - OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m
          - DISABLE_INSTALL_DEMO_CONFIG=true
          - DISABLE_SECURITY_PLUGIN=true
        ulimits:
          memlock:
            soft: -1
            hard: -1
          nofile:
            soft: 65536
            hard: 65536
        volumes:
          - opensearch-data2:/usr/share/opensearch/data
    
      opensearch-dashboards:
        image: opensearchproject/opensearch-dashboards:2.13.0
        container_name: opensearch-dashboards
        ports:
          - 5601:5601
        expose:
          - "5601"
        environment:
          - OPENSEARCH_HOSTS=["http://opensearch-node1:9200","http://opensearch-node2:9200"]
          - DISABLE_SECURITY_DASHBOARDS_PLUGIN=true
    
      zookeeper:
        image: bitnami/zookeeper:3.9
        container_name: zookeeper
        restart: always
        ports:
          - "2181:2181"
        volumes:
          - zookeeper_data:/bitnami
        environment:
          - ALLOW_ANONYMOUS_LOGIN=yes
    
      kafka:
        image: bitnami/kafka:3.4
        container_name: kafka
        restart: always
        hostname: kafka
        ports:
          - '9092:9092'
          - '9094:9094'
        environment:
          - KAFKA_CFG_NODE_ID=0
          - KAFKA_CFG_PROCESS_ROLES=controller,broker
          - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://0.0.0.0:9094
          - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://192.168.110.110:9094
          - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT
          - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=0@kafka:9093
          - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
          - ALLOW_PLAINTEXT_LISTENER=yes
          - KAFKA_HEAP_OPTS=-Xmx512m -Xms512m
        volumes:
          - kafka-conf:/bitnami/kafka/config
          - kafka-data:/bitnami/kafka/data
    
      kafka-ui:
        container_name: kafka-ui
        image: provectuslabs/kafka-ui:latest
        restart: always
        ports:
          - 8080:8080
        environment:
          - DYNAMIC_CONFIG_ENABLED=true
          - KAFKA_CLUSTERS_0_NAME=kafka-dev
          - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka:9092
        volumes:
          - kafkaui-app:/etc/kafkaui
    
      nacos:
        image: nacos/nacos-server:v2.3.1
        container_name: nacos
        ports:
          - 8848:8848
          - 9848:9848
        environment:
          - PREFER_HOST_MODE=hostname
          - MODE=standalone
          - JVM_XMX=512m
          - JVM_XMS=512m
          - SPRING_DATASOURCE_PLATFORM=mysql
          - MYSQL_SERVICE_HOST=nacos-mysql
          - MYSQL_SERVICE_DB_NAME=nacos_devtest
          - MYSQL_SERVICE_PORT=3306
          - MYSQL_SERVICE_USER=nacos
          - MYSQL_SERVICE_PASSWORD=nacos
          - MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
          - NACOS_AUTH_IDENTITY_KEY=2222
          - NACOS_AUTH_IDENTITY_VALUE=2xxx
          - NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789
          - NACOS_AUTH_ENABLE=true
        volumes:
          - /app/nacos/standalone-logs/:/home/nacos/logs
        depends_on:
          nacos-mysql:
            condition: service_healthy
    
      nacos-mysql:
        container_name: nacos-mysql
        image: nacos/mysql:8.0.30
        environment:
          - MYSQL_ROOT_PASSWORD=root
          - MYSQL_DATABASE=nacos_devtest
          - MYSQL_USER=nacos
          - MYSQL_PASSWORD=nacos
          - LANG=C.UTF-8
        volumes:
          - nacos-mysqldata:/var/lib/mysql
        ports:
          - "13306:3306"
        healthcheck:
          test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
          interval: 5s
          timeout: 10s
          retries: 10
    
      prometheus:
        image: prom/prometheus:v2.52.0
        container_name: prometheus
        restart: always
        ports:
          - 9090:9090
        volumes:
          - prometheus-data:/prometheus
          - prometheus-conf:/etc/prometheus
    
      grafana:
        image: grafana/grafana:10.4.2
        container_name: grafana
        restart: always
        ports:
          - 3000:3000
        volumes:
          - grafana-data:/var/lib/grafana
    
    volumes:
      redis-data:
      redis-conf:
      mysql-conf:
      mysql-data:
      rabbit-data:
      rabbit-app:
      opensearch-data1:
      opensearch-data2:
      nacos-mysqldata:
      zookeeper_data:
      kafka-conf:
      kafka-data:
      kafkaui-app:
      prometheus-data:
      prometheus-conf:
      grafana-data:
    
  3. 启动容器

    docker compose up -d