docker、docker compose、docker swarm使用笔记

Docker 基础命令指南

本文详细介绍了docker中常用的命令,并且通过实际的例子介绍了如何使用docker compose, docker swarm部署多副本应用。

帮助命令

帮助文档地址:Docker官方参考文档

Docker的帮助命令可以用来获取不同命令的详细信息。

docker version         # 查看Docker版本
docker info            # 获取Docker系统信息
docker 命令 --help     # 获取特定Docker命令的帮助信息

帮助命令

docker version
docker info
docker 命令 --help #帮助命令

镜像命令

查看镜像

列出本地存储的所有镜像。

sudo docker images

搜索镜像

在Docker Hub中搜索镜像。

sudo docker search nginx

下载镜像

Docker Hub拉取镜像。

sudo docker pull [镜像名称]:[tag]
# 拉取openjdk 11
sudo docker pull openjdk:11-jre
# 拉取nginx latest
sudo docker pull nginx

删除镜像

删除指定的本地镜像。

# 不加-f的话,如果有container用了这个image,那就会报错删不掉这个
# 或者可以手动先把相应的container删除
sudo docker rmi -f [镜像名字或者id或者id的前几个字母]

基于Dockerfile构建镜像

根据Dockerfile创建新镜像。

# 假设Dockerfile在当前目录
docker build -t [镜像名称]:[tag] [Dockerfile所在目录]

# 比如镜像名称是myapp-1.0-SNAPSHOT.jar,设置tag为1.0
# dockerfile里面需要的文件也要在当前目录下,比如jar包
docker build -t myapp-1.0-SNAPSHOT.jar .

容器命令

创建并启动容器

使用docker run命令来创建并启动一个容器。

sudo docker run [可选参数] image

# 参数说明
--name="Name"    # 容器命名
-d               # 以后台方式运行
-it              # 使用交互方式运行,进入容器查看内容
-p               # 指定容器的端口 -p 8080:8080
                 # -p 主机端口:容器端口
                 # -p ip:主机端口:容器端口
-P               # (大写P)随机指定端口

列出容器

显示当前正在运行的容器信息。

sudo docker ps

# 参数说明
-a      # 列出当前运行的及历史运行过的容器
-n=?    # 显示最近创建的容器
-q      # 只显示容器编号

退出容器

退出当前容器的方法。

exit            # 停止并退出
ctrl + P + Q    # 容器不停止退出

删除容器

删除指定的容器。

docker rm [容器名字或者id或者id的前几个字母]

启动和停止容器

对容器进行启动、重启、停止和强制停止操作。

docker start   # 启动容器
docker restart # 重启容器
docker stop    # 停止容器
docker kill    # 强制停止容器

容器网络相关

创建网络

创建Docker网络。

docker network create mynet

连接容器到网络

将指定容器连接到网络。

docker network connect mynet [containerId]

查看网络详情

查看网络详情,包括连接到网络的容器。

docker inspect mynet

查看所有网络

列出所有Docker网络。

docker network ls

Docker其他常用命令

后台启动容器

在后台运行容器,需要确保有一个前台进程。

docker run -d 镜像名

查看日志

查看容器日志。

docker logs 容器id

查看容器内进程

查看容器内部的进程信息

docker top 容器id

查看镜像元数据

dokcer inspect 容器id

进入运行中的容器

进入当前正在运行的容器。

# 方法一:进入容器后开启新窗口
docker exec -it 容器id bashshell

# 方法二:进入正在执行的容器窗口,不启动新进程
docker attach 容器id

从容器内拷贝文件

将容器内的文件拷贝到主机上。

docker cp container_id:/path/to/file /path/to/host/file

Dockerfile相关

Dockerfile主要是用来构建docker镜像的。

Dockerfile结构解读

  1. 文件名:Dockerfile
  2. 保留字命令必须全大写
  3. 每行只能有一条指令
  4. # 表示注释
  5. 指令从上到下执行
  6. 每条指令都会创建一个新的镜像层,所以指令少一点比较好,省空间

基于Dockerfile构建镜像

保留命令

# 当前镜像是基于哪个镜像的,第一个指令必须是FROM,比如下面就是以最新的
FROM alpine:3.15

# 镜像维护者的姓名和邮箱地址(废弃了)
MAINTAINER

# 可以使用shell语法
RUN yum install -y vim
# 也可以使用下面这种
RUN ["yum", "install", "-y", "vim"]

# 当前容器对外暴露的端口号(只是声明,给别人看的,没有实际的影响,可以写在除了第一行以外的任何一行)
EXPOSE 8080

# 指定在创建容器后,终端默认登录进来的容器内的工作目录, 这个命令之后的操作都是在这个目录里面进行
# 如果不存在这个目录,会自动创建,可以绝对路径,也可以相对路径,默认是在根目录
WORKDIR /apps


# 比如,设置一个变量BASE_PATH, 然后用这个 变量的时候需要用$符号
ENV BASE_PATH=/apps/data
WORKDIR $BASE_PATH

# 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL
# 比如把dockerfile所在文件目录的aa.txt文件拷贝到容器内/apps/data目录
ADD ./aa.txt /apps/data
# 也可以直接用容器内的当前目录
ADD ./aa.txt ./data
# 如果是url,会自动下载文件,拷贝到容器里面
ADD https://download.apache.org/tomcat/tomcat-9/v9.0.48/bin/apache-tomcat-9.0.48.tar.gz ./data


# 拷贝文件和目录到镜像中,跟add类似,但只能从文件上下文拷贝文件,不能通过url
# 比如下面的命令就是把宿主机上当前Dockerfile所在目录下的my-app-1.0-SNAPSHOT.jar复制到容器内工作目录,并重命名为app.jar
COPY my-app-1.0-SNAPSHOT.jar app.jar

# 容器数据卷,用于数据保存和持久化工作(仅仅是一个声明,告诉使用者可以挂在这个目录到宿主机中), 比如声明容器内当前工作目录的data文件夹为挂载点
VOLUME ./data

# 指定一个容器启动时要运行的命令, dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换
CMD

# 指定一个容器启动时要运行的命令, ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及其参数
# CMD和ENTRYPOINT的语法,都是可以使用shell命令或者字符串数组的形式,推荐后者
ENTRYPOINT


# CMD和ENTRYPOINT区别是什么?
# CMD: docker run 镜像:版本号 覆盖自己定义的命令
# ENTRYPOINT: docker run --entrypoint=覆盖指令 镜像:版本号 传递参数

# 假设dockerfile有以下两行内容
FROM ubuntu
CMD ["echo", "Hello World"]
# 如果运行`docker run -it myImage`, 会输出"Hello World"
# 但如果运行`docker run -it myImage /bin/bash`, 就会进入 bash,并且 CMD 指定的命令不会被执行。

# 假设dockerfile有以下两行内容
FROM ubuntu
ENTRYPOINT ["echo"]
# 如果运行`docker run -it myImage`, 不会输出任何内容, 因为没有给echo指定参数
# 如果运行`docker run -it myImage "Hello World"`, 它会输出 "Hello World",因为 "Hello World" 被作为参数传递给了 ENTRYPOINT。

# 所以一般这两个命令配合起来使用,以便于更换命令之后的参数,而不覆盖命令本身,比如
ENTRYPOINT ["java", "-jar"]
CMD ["/apps/data/nblog.jar"]

Dockerfile构建镜像

注意,Dockerfile所在的目录的文件都会被发送到docker engine,
所以最好弄个新文件夹,或者同级目录不要有无关的文件,
以减少构建上下文的大小,提高镜像构建的效率。

# 根据当前目录下的Dockerfile文件,构建出mycentos镜像,标签为latest
# 注意后面有个英文句号,代表当前目录
docker build -t mycentos:latest .

Dockerfile构建镜像实战

下面来通过几个例子来巩固上面的知识

构建jdk21镜像

为了能够部署基于jdk21的java项目,我们需要一个装有jdk21的linux镜像作为基础镜像,下面开始构建。

  1. 编写Dockerfile
# 首先创建一个空目录方便后续操作
mkdir $HOME/docker-tmp
cd $HOME/docker-tmp
# 创建Dockerfile文件
touch Dockerfile
vim Dockerfile

将下面内容写入Dockerfile:

# alpine是一个轻量化的linux镜像
FROM alpine:3.15

ARG version=21.0.0.34.1

# Please note that the THIRD-PARTY-LICENSE could be out of date if the base image has been updated recently.
# The Corretto team will update this file but you may see a few days' delay.
RUN wget -O /THIRD-PARTY-LICENSES-20200824.tar.gz https://corretto.aws/downloads/resources/licenses/alpine/THIRD-PARTY-LICENSES-20200824.tar.gz && \
    echo "82f3e50e71b2aee21321b2b33de372feed5befad6ef2196ddec92311bc09becb  /THIRD-PARTY-LICENSES-20200824.tar.gz" | sha256sum -c - && \
    tar x -ovzf THIRD-PARTY-LICENSES-20200824.tar.gz && \
    rm -rf THIRD-PARTY-LICENSES-20200824.tar.gz && \
    wget -O /etc/apk/keys/amazoncorretto.rsa.pub https://apk.corretto.aws/amazoncorretto.rsa.pub && \
    SHA_SUM="6cfdf08be09f32ca298e2d5bd4a359ee2b275765c09b56d514624bf831eafb91" && \
    echo "${SHA_SUM}  /etc/apk/keys/amazoncorretto.rsa.pub" | sha256sum -c - && \
    echo "https://apk.corretto.aws" >> /etc/apk/repositories && \
    apk add --no-cache amazon-corretto-21=$version-r0 && \
    rm -rf /usr/lib/jvm/java-21-amazon-corretto/lib/src.zip


ENV LANG C.UTF-8

ENV JAVA_HOME=/usr/lib/jvm/default-jvm
ENV PATH=$PATH:/usr/lib/jvm/default-jvm/bin
  1. 构建镜像

假设将镜像命名为21-jdk-alpine

docker build -t 21-jdk-alpine .
  1. 查看镜像
docker images

可以看到名为21-jdk-alpine:latest的镜像已经构建好了

  1. 推送镜像到docker hub(可选)

如果想要把镜像推送到docker hub公共仓库或者私有仓库,方便自己后续使用的话,可以按下面步骤操作:

参考官方文档 hub.docker.io

# 先登录docker
docker login --username=myuname
# 输入密码之后,可以看到Login Succeeded,说明登录成功了,然后推送image
docker push 21-jdk-alpine:latest

Docker compose相关

首先关于docker compose和docker-compose这两个命令,docker compose是V2版,目前和以后使用的命令,docker-compose是V1版,会逐渐废弃,所以后续都使用docker-compose

docker compose安装

docker compose在windows和macos上是随docker一起安装的,但在linux上没有,所以linux上需要单独安装docker compose。
docker compose的安装就是把一个sh文件下下来放到指定的位置就行(/usr/local/bin/docker-compose)
安装方式,在线安装:

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m`" > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

启动服务

必须在docker-compose.yml的目录执行。
可以针对项目或者项目的某个service, 如果没有指定,则默认时针对整个项目。

不管服务有没有创建过,都重新构建并重启服务

# 服务不存在则构建并启动,服务已存在则直接重启(已有镜像的话不会重新构建)
docker compose up

# 参数解释
-f       # 指定docker-compose.yml文件名,默认会找docker-compose.yml
-d       # 后台启动
--build  # 构建服务

# 例子: 根据当前目录下的docker-compose.yml文件构建myservice
docker compose build myservice

# 例子: 根据当前目录下的docker-compose.yml文件重新构建(文件中设定了build的)并重启文件里的所有服务,后台启动
docker compose up --build -d

# 例子:在上面的基础上,指定文件里的名为myservice的服务
docker compose up --build -d myservice

启动已经创建过的服务

docker compose start

进入某个服务内部

docker compose exec 服务id bash

列出所有运行的服务

docker compose ps

查看compose所有服务的日志

docker compose logs -f

暂停/停止/删除服务


# 暂停服务
docker-componse pause

# 恢复服务
docker-compose unpause

# 停止服务
docker compose stop

# 删除服务(会关闭里面的所有容器, 并删除网络)
docker compose down

# 删除指定服务
docker compose rm myservice

# 选项说明
-f         # 强制删除,即使有运行中的container
-v         # 删除相关的数据卷

# 重启相关,比如重启名为myservice的服务
# 重启所有开启中的服务 
docker compose restrat

# 重启指定服务
docker compose restart myservice

# 10秒后重启指定服务
docker compose -t 10 restart myservice

Docker swarm相关

docker swarm是docker自带的容器编排管理工具,对于比较小型的应用,使用docker swarm多副本部署项目完全足够了。
简单介绍一下docker swarm的优点:

  1. 一个服务可以开多个副本,这些副本全部共用一个端口,docker swarm自动对容器内的副本进行负载均衡
  2. 简单易用:Docker Swarm内置于Docker Engine中,无需安装额外的组件,使用起来相对简单。
  3. 高可用性:Docker Swarm支持高可用部署,可以容忍节点故障,保证服务的高可靠性。
  4. 横向扩展:Docker Swarm支持服务的横向扩展,可以根据需求动态增加或减少服务实例。

初始化docker swarm

首先之前如果没有使用过docker swarm,需要初始化一下docker swarm

# 初始化docker swarm
docker swarm init

# 或者指定当前节点的ip,方便其他的节点加入
docker swarm init --advertise-addr 192.168.31.12

init完成之后,会有如下提示,可以把key记下来,方便以后其他节点join进来

Swarm initialized: current node (7ko7fomyjbvztcrnx5ndzhlv2) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-013ti9s1yywzuqn7j4z534f26vee83ljx1z4oe4t11vo8koyh2-2yfn82ze8g7enm8pfku0r5l20 192.168.31.12:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

启动/重启/删除服务,日志查看

下面的clientapp是自定义的stack name, 后面需要用到

# 根据当前目录下的docker-compose.yml启动名为myapp的stack
docker stack deploy -c docker-compose.yml myapp

# 查看现有的stack
docker stack ls

# 查看服务的状态
docker service ls

# 查看stack里所有service的状态
docker stack ps myapp

# 查看myapp_service01的状态
docker service ps myapp_service01

# 查看日志
# 目前不支持直接看整个stack的日志,只能单独看docker-compose.yml里面每个service的日志
# 比如docker-compose.yml有个名为service01的服务,则需要用下划线拼接stack和service,如下所示:
docker services logs -f myapp_service01

# 选项说明
--follow        # 实时查看日志
--tail [n]         # 只看尾部n行的日志

# 删除名为myapp的stack
docker stack rm myapp

# 强制使用image重启服务
# 下面指令意思是使用service01-image:latest镜像重启myapp这个stack里面的service01服务
docker service update --force --image service01-image:latest myapp_service01

docker swarm实战:发版服务

实操任务描述:现在有个java springboot项目,已经通过maven打包好了名为myapp-1.0-SNAPSHOT.jar的jar包,需要部署到云服务上

  1. 登录云服务器(或者本地搞个虚拟机)
  2. 假定工作目录为/root/docker-deploy,将myapp-1.0-SNAPSHOT.jar传输到该目录
  3. 在该目录创建Dockfile文件,写入如下内容:
FROM openjdk:21-jdk-alpine

ENV TZ=Asia/Shanghai \
    APP_PATH=/data \
    JAVA_OPTS="-Xms256m -Xmx256m"

WORKDIR $APP_PATH

COPY myapp-1.0-SNAPSHOT.jar app.jar

EXPOSE 8080

ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -jar app.jar" ]
  1. 构建镜像
docker build -t myapp-image .
  1. 创建docker-compose.yml文件,写入如下内容
version: "3.8"
services:
  service01:
    image: myapp-image:latest # 确保构建好您的镜像,并替换此处
    ports:
      - "8080:8080" # Swarm 将自动负载均衡到所有副本
    extra_hosts:
      - "host.docker.internal:host-gateway" # 设定宿主机host地址,方便容器内服务通过http://host.docker.internal:[端口号]访问宿主机的服务
    deploy:
      replicas: 3 # 设置您需要的副本数量
      update_config:
        parallelism: 1 # 每次更新一个副本
        delay: 30s # 更新之间的延迟
        order: start-first # 首先启动新容器,然后停止旧容器
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
    networks:
      - mynet
    volumes:
      - myapplog:/data/logs # 使用单个卷,或根据需要调整
    environment:
      - "SPRING_PROFILES_ACTIVE=prod"

volumes:
  myapplog:

networks:
  mynet:

  1. 部署启动服务
docker stack deploy -c docker-compose.yml myapp
  1. 查看服务启动状况

这里需要等一会儿,看到replicas 3/3说明所有副本都启动成功

# 查看stack是否创建成功
docker stack ls

# 查看服务状态
docker service ls

# 查看服务日志
docker service logs -f myapp_service01

# 或者可以直接看volume里面的挂载的日志文件
# 1.先找到volume在宿主机实际的存储地址,注意这个volume是要加上stack的名称的
# 可以用docker volume ls看看有哪些存储卷
docker volume inspect myapp_myapplog
# 找到Mountpoint,然后进入目录找到对应的日志文件即可
cd /var/lib/docker/volumes/myapp_myapplog/_data

docker swarm实战:不停机更新服务

下面介绍一下如何不停机更新发版。
在上面的docker-compose.yml的deploy中,我们已经配置了重启的策略,就是重启的时候先启动新的容器,再停掉旧的容器,这样就可以实现用户无感知,不停机更新发版

  1. 把更新后的代码打包好,把jar包传输到/root/docker-deploy
  2. 构建镜像
cd /root/docker-deploy
docker build -t myapp-image .
  1. 强制使用新的image重启服务
docker service update --force --image myapp-image:latest myapp_service01
  1. 查看启动日志
docker service logs -f myapp_service01

docker 仓库相关

修改镜像的tag

docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

登录远程仓库

# 登录远程镜像仓库(后面不加host就是默认登录docker hub)
docker login --username=[你的docker hub账号名称]

# 或者登录指定的仓库,比如阿里云镜像
docker login --username=myaliname registry.cn-hangzhou.aliyuncs.com

从指定远程仓库拉取镜像

# 假设从阿里云私有镜像拉取
docker pull registry.cn-hangzhou.aliyuncs.com/myrepo/myapp:1.0.0

推送本地镜像到远程仓库

# 先登录远程镜像仓库
docker login --username=myaliname registry.cn-hangzhou.aliyuncs.com

# 修改镜像tag,设定镜像地址
docker tag [需要推送的镜像id] [仓库地址]:[镜像版本号]
# 比如:
docker tag 99dcb1016b23 registry.cn-hangzhou.aliyuncs.com/myrepo/myapp:1.0.0

# 推送镜像到远程镜像仓库
docker push registry.cn-hangzhou.aliyuncs.com/myrepo/myapp:1.0.0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值