Java程序员的Docker实战秘籍

个人主页:java之路-优快云博客(期待您的关注)

目录

引言

Docker 基础概念快速入门

什么是 Docker

Docker 核心组件

Docker 安装与环境配置

不同系统安装步骤

配置国内镜像源

Docker 在 Java 项目中的实践应用

Java Web 项目部署

数据库服务容器化

微服务架构中的应用

Docker 使用技巧与优化

镜像构建优化

容器资源管理

常见问题与解决方法


引言

在 Java 开发的漫长征程中,我们常常遭遇各种棘手的问题。曾经,我参与一个大型电商项目的开发,在本地开发环境中,一切运行得如丝般顺滑,可当代码部署到测试环境时,却频繁报错。经过漫长而艰难的排查,才发现是开发环境与测试环境的 JDK 版本不一致,以及依赖包的版本冲突所致。这种环境不一致的问题,就像隐藏在暗处的 “幽灵”,严重影响开发效率,增加项目成本。

随着容器化技术的兴起,Docker 犹如一道曙光,照亮了 Java 开发与部署的道路。它通过将应用程序及其依赖项打包成一个独立的容器,实现了 “一次构建,到处运行”,彻底解决了环境不一致的难题。无论是开发、测试还是生产环境,Docker 容器都能确保应用程序以相同的方式运行,大大提高了开发和部署的效率。在接下来的内容中,我将深入探讨 Docker 的实践与应用,分享其在 Java 项目中的具体使用方法和实际案例 。

Docker 基础概念快速入门

什么是 Docker

Docker,简单来说,是一个开源的应用容器引擎 ,可以让开发者将应用程序及其依赖项打包到一个可移植的容器中,然后发布到任何流行的 Linux 或 Windows 操作系统的机器上运行。它就像是一个 “软件集装箱”,把应用程序和它运行所需要的各种环境、依赖都封装在里面,保证这个应用无论在什么地方运行,它的环境都是一模一样的。

我们可以用集装箱来形象地比喻 Docker。在运输行业中,集装箱能将不同种类的货物进行标准化封装,不管是衣物、食品还是电子产品,都能装进集装箱中。这些集装箱规格统一,便于在不同的运输工具(如轮船、火车、卡车)之间转运,而且相互之间不会产生干扰。同样,Docker 将应用程序及其依赖(如运行时环境、库、配置文件等)打包成一个标准化的容器。这个容器可以在不同的计算环境(如物理机、虚拟机、公有云、私有云)中轻松部署和运行,并且各个容器之间相互隔离,互不影响。

与传统的虚拟机相比,Docker 具有诸多显著优势。传统虚拟机需要在硬件层面通过 Hypervisor(如 VMware ESXi、KVM 等)模拟出完整的硬件环境,然后在这个模拟环境上安装和运行操作系统,最后再在操作系统中部署应用程序。这就好比在一个大房子里隔出多个小房间,每个小房间都配备一套完整的生活设施(包括床、桌椅、厨房设备等),然后让人在里面生活。而 Docker 则是利用操作系统内核的特性(如 Linux 的 cgroup 和 namespace),在操作系统层面实现虚拟化。它不需要模拟硬件环境,而是直接在宿主机的操作系统上运行应用程序,各个应用程序之间通过容器进行隔离。这就像是在一个大房子里,大家共享公共设施(如客厅、卫生间等),但每个人都有自己独立的小空间(如卧室),可以自由布置和使用。

相比之下,Docker 更加轻量级,启动速度更快,对系统资源的利用率也更高。传统虚拟机启动一个完整的操作系统通常需要几十秒甚至几分钟,而 Docker 容器由于无需启动操作系统,启动时间可以达到秒级甚至毫秒级。在资源利用方面,传统虚拟机每个都需要占用大量的内存、CPU 和磁盘空间来运行操作系统,而 Docker 容器共享宿主机的操作系统内核,只需要占用应用程序运行所需的资源,大大提高了资源的利用率。

Docker 核心组件

Docker 主要包含三个核心组件:镜像(Image)、容器(Container)和仓库(Repository)。

  • 镜像(Image):可以将其视为一个只读的模板,包含了运行应用程序所需的所有内容,如代码、运行时环境、系统工具、库以及设置等。以 Java 项目为例,Java 项目的镜像中会包含 Java 运行时环境(JRE)、项目的依赖库(如 Spring Boot 框架、数据库连接驱动等)、项目的打包文件(如 JAR 包或 WAR 包)以及一些启动配置文件。我们可以通过编写 Dockerfile 来定义如何构建镜像,例如:
    # 使用官方的OpenJDK 11作为基础镜像
    FROM openjdk:11
    # 将本地的JAR包复制到容器中的/app目录下
    COPY target/my-java-app.jar /app/
    # 设置工作目录为/app
    WORKDIR /app
    # 定义容器启动时执行的命令,运行JAR包
    CMD ["java", "-jar", "my-java-app.jar"]

在这个例子中,我们首先指定了基于 OpenJDK 11 的基础镜像,然后将本地项目打包生成的 JAR 包复制到容器的指定目录,并设置了工作目录和容器启动时执行的命令。通过这个 Dockerfile,我们就可以构建出一个包含 Java 项目运行所需一切的镜像。

  • 容器(Container):容器是镜像的运行实例,它可以被启动、停止、删除等操作。当我们基于一个 Java 项目的镜像启动容器时,就相当于创建了一个独立的运行环境来运行这个 Java 项目。每个容器都有自己独立的文件系统、网络空间和进程空间,与其他容器以及宿主机相互隔离。例如,我们可以使用以下命令基于刚才构建的 Java 项目镜像启动一个容器:
    docker run -d -p 8080:8080 my-java-app:1.0

这个命令中,-d表示以守护进程模式在后台运行容器,-p 8080:8080表示将容器内部的 8080 端口映射到宿主机的 8080 端口,这样我们就可以通过访问宿主机的 8080 端口来访问容器中运行的 Java 应用程序,my-java-app:1.0则是指定要运行的镜像名称和版本。

  • 仓库(Repository):仓库是集中存放镜像文件的地方,类似于代码仓库。我们可以将自己构建的镜像推送到仓库中,也可以从仓库中拉取其他人共享的镜像。Docker 官方提供了一个公共仓库 Docker Hub,其中包含了大量的官方镜像和用户上传的镜像。此外,我们也可以搭建自己的私有仓库,用于存储和管理公司内部的镜像。例如,在 Java 开发中,如果我们开发了一个通用的 Java 基础服务镜像,就可以将其推送到私有仓库中,方便团队内其他项目使用。推送镜像到仓库的命令如下:
    docker push my-private-registry.com/my-java-base-service:1.0

拉取镜像的命令则是:

docker pull my-private-registry.com/my-java-base-service:1.0

理解和掌握 Docker 的这三个核心组件,是深入学习和使用 Docker 进行 Java 项目开发和部署的基础。

Docker 安装与环境配置

不同系统安装步骤

  • Linux 系统:以 CentOS 为例,安装步骤如下:
  1. 卸载旧版本(可选):如果之前安装过旧版本的 Docker,可以使用以下命令卸载:
    sudo yum remove docker \
                      docker-client \
                      docker-client-latest \
                      docker-common \
                      docker-latest \
                      docker-latest-logrotate \
                      docker-logrotate \
                      docker-selinux \
                      docker-engine-selinux \
                      docker-engine \
                      docker-ce
  2. 安装依赖包:yum-utils 提供了 yum-config-manager,并且 device mapper 存储驱动程序需要 device-mapper-persistent-data 和 lvm2。
    sudo yum install -y yum-utils \
      device-mapper-persistent-data \
      lvm2 --skip-broken
  3. 更新本地镜像源:将数据源设置为阿里云的镜像源,提高下载速度。
    sudo yum-config-manager \
        --add-repo \
        https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  4. 安装 Docker
    sudo yum install -y docker-ce
  5. 启动 Docker 服务
    sudo systemctl start docker
  6. 验证安装:通过运行 hello-world 镜像来验证是否正确安装了 Docker。
    docker run hello-world
  • Windows 系统
  1. 环境准备:Docker for Windows 运行在 64 位 Windows 10 Pro、企业版和教育版(不支持家庭版)。需要检查电脑的虚拟化是否开启,右键电脑左下角开始按钮,选择 “任务管理器”,在 “性能” 选项卡中查看 CPU 的虚拟化是否已启用。如果虚拟化显示已禁用,需要重启电脑进入 BIOS 开启虚拟化。然后左键单击电脑左下角开始按钮,选择 “设置”,搜索 “Windows 功能”,启用或关闭 Windows 功能,勾选 “Hyper - v”,启用后电脑会重启。
  2. 下载安装包:从Docker 官方下载页面下载 Docker Desktop 安装包。
  3. 安装:双击下载的安装包进行安装,安装完成后,打开 Docker Desktop 应用程序。在系统托盘中,可以看到 Docker 图标。点击 Docker 图标,选择 “Settings” 菜单,进入 Docker 设置页面,可以在其中设置 Docker 的启动项、资源分配(如 CPU 和内存使用量)以及网络和代理设置等。
  4. 验证安装:打开命令行终端,输入docker version,如果正确安装,将会显示 Docker 的版本信息。
  • MacOS 系统
  1. 检查系统版本:Docker 官方建议 MacOS 必须是版本 11 或更高版本,如果版本较低,建议先升级 MacOS 版本。可以通过左上角的苹果图标查看系统版本,并通过 “软件更新” 来检查和更新 MacOS 系统。
  2. 下载安装:通过Docker 下载链接下载 Mac 系统的 Docker 程序。下载完成后,双击.dmg文件,然后将 Docker 鲸鱼图标拖拽到 “Application” 文件夹即完成安装。
  3. 运行 Docker:在应用程序中找到 Docker 程序图标,点击以启动 Docker,启动之后会发现右上角工具栏中多了一个小鲸鱼的图片,这就是 Docker。通过小鲸鱼中的 “About Docker Desktop” 可以查看 Docker 的版本,也可以通过docker --version命令查看版本。通过docker info命令可以查看 Docker Client 端和 Server 端信息。

配置国内镜像源

在国内使用 Docker 时,由于默认的 Docker 官方镜像源在国外,拉取镜像的速度可能会很慢,甚至出现超时失败的情况。为了解决这个问题,我们可以配置国内的镜像源,如阿里云、网易云等。下面以阿里云镜像源为例,介绍配置镜像源的步骤:

  1. 登录阿里云:访问阿里云官网,登录账号后,在搜索框中输入 “容器镜像服务”,进入容器镜像服务页面。
  2. 获取镜像加速器地址:在容器镜像服务页面中,找到 “镜像工具” - “镜像加速器”,根据自己的操作系统选择对应的配置命令,这里会显示一个专属的镜像加速器地址,如https://xxxx.mirror.aliyuncs.com
  3. 配置镜像源
  • Linux 系统
  •     创建/etc/docker目录(如果目录已存在则跳过):
    sudo mkdir -p /etc/docker
  • 创建或编辑/etc/docker/daemon.json文件,添加镜像加速器地址:
    sudo tee /etc/docker/daemon.json <<-'EOF'
    
    {
    
    "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
    
    }
    
    EOF
  • 重新加载配置文件并重启 Docker 服务:
    sudo systemctl daemon-reload
    
    sudo systemctl restart docker
  • Windows 系统
  • 打开 Docker Desktop 应用程序,点击系统托盘中的 Docker 图标,选择 “Settings”。
  • 在左侧导航栏中选择 “Docker Engine”,在右侧的编辑框中,添加或修改registry-mirrors字段,将镜像加速器地址添加进去,如下所示:
    {
    
    "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
    
    }
  • 点击 “Apply & Restart” 按钮,Docker 会重启并应用新的镜像源配置。
  • MacOS 系统
  • 打开 Docker Desktop 应用程序,点击菜单栏中的 “Docker”,选择 “Preferences”。
  • 在左侧导航栏中选择 “Docker Engine”,在右侧的编辑框中,添加或修改registry-mirrors字段,将镜像加速器地址添加进去,如下所示:
    {
    
    "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
    
    }
  • 点击 “Apply & Restart” 按钮,Docker 会重启并应用新的镜像源配置。

配置完成后,可以通过docker info命令查看配置是否生效,在输出信息中找到 “Registry Mirrors” 字段,如果显示的是配置的镜像源地址,则说明配置成功 。

Docker 在 Java 项目中的实践应用

Java Web 项目部署

以 Spring Boot 项目为例,展示如何使用 Docker 进行部署。假设我们有一个简单的 Spring Boot 项目,提供一个 RESTful 接口,用于获取用户信息。

  1. 创建 Spring Boot 项目
    • 使用 Spring Initializr(https://start.spring.io/ )创建一个新的 Spring Boot 项目,选择Spring Web依赖。
    • 创建一个简单的控制器类UserController.java:
      package com.example.demo.controller;
      
      import org.springframework.web.bind.annotation.GetMapping;
      
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      
      public class UserController {
      
      @GetMapping("/user")
      
      public String getUser() {
      
      return "Hello, User!";
      
      }
      
      }

  1. 编写 Dockerfile:在项目根目录下创建一个Dockerfile文件,内容如下:
    # 使用官方的OpenJDK 11作为基础镜像
    
    FROM openjdk:11
    
    # 将本地的JAR包复制到容器中的/app目录下
    
    COPY target/demo-0.0.1-SNAPSHOT.jar /app/
    
    # 设置工作目录为/app
    
    WORKDIR /app
    
    # 定义容器启动时执行的命令,运行JAR包
    
    CMD ["java", "-jar", "demo-0.0.1-SNAPSHOT.jar"]
  2. 构建镜像:在项目根目录下执行以下命令构建镜像:
    docker build -t my-spring-boot-app:1.0.0.

这里-t参数用于指定镜像的标签,格式为镜像名:版本号,最后的.表示当前目录,即 Dockerfile 所在的目录。

4. 运行容器:构建完成后,使用以下命令运行容器:

docker run -d -p 8080:8080 my-spring-boot-app:1.0.0

-d参数表示以后台守护进程模式运行容器,-p 8080:8080表示将容器内部的 8080 端口映射到宿主机的 8080 端口,这样我们就可以通过访问宿主机的 8080 端口来访问 Spring Boot 应用的/user接口,即http://localhost:8080/user

数据库服务容器化

以 MySQL 为例,讲述如何使用 Docker 容器化数据库服务。

  1. 拉取镜像:使用以下命令拉取 MySQL 8.0 的镜像:
    docker pull mysql:8.0
  2. 运行容器:运行 MySQL 容器,并设置环境变量和数据持久化:
    docker run -d \
    
    -p 3306:3306 \
    
    --name my-mysql \
    
    -e MYSQL_ROOT_PASSWORD=root \
    
    -v /data/mysql:/var/lib/mysql \
    
    mysql:8.0
  • -d:以后台守护进程模式运行容器。
  • -p 3306:3306:将容器的 3306 端口映射到宿主机的 3306 端口。
  • --name my-mysql:给容器命名为my-mysql。
  • -e MYSQL_ROOT_PASSWORD=root:设置 MySQL 的 root 用户密码为root。
  • -v /data/mysql:/var/lib/mysql:将宿主机的/data/mysql目录挂载到容器的/var/lib/mysql目录,实现数据持久化,即使容器被删除,数据也不会丢失。
  1. 设置环境变量:除了设置MYSQL_ROOT_PASSWORD,还可以设置其他环境变量,如:
  • MYSQL_DATABASE:创建一个新的数据库。
  • MYSQL_USER和MYSQL_PASSWORD:创建一个新的用户并设置密码。

例如,创建一个名为mydb的数据库,一个名为myuser,密码为mypassword的用户:

docker run -d \

-p 3306:3306 \

--name my-mysql \

-e MYSQL_ROOT_PASSWORD=root \

-e MYSQL_DATABASE=mydb \

-e MYSQL_USER=myuser \

-e MYSQL_PASSWORD=mypassword \

-v /data/mysql:/var/lib/mysql \

mysql:8.0
  1. 实现数据持久化:通过上述的-v参数挂载目录,MySQL 的数据文件(如.ibd文件、日志文件等)会存储在宿主机的/data/mysql目录下。当容器重新启动或被删除重建时,只要宿主机的/data/mysql目录存在且权限正确,MySQL 的数据就会被保留。可以通过在 MySQL 容器中创建数据库、表并插入数据,然后停止容器,删除容器,再重新创建并启动容器,验证数据是否依然存在。

微服务架构中的应用

结合 Spring Cloud 微服务架构,使用 Docker Compose 编排微服务。假设我们有一个简单的微服务架构,包含一个服务注册中心(Eureka Server)、一个服务提供者(User Service)和一个服务消费者(Order Service)。

  1. 创建 Spring Cloud 微服务项目
  • Eureka Server:创建一个 Spring Boot 项目,添加spring-cloud-starter-netflix-eureka-server依赖,配置文件application.yml如下:
    server:
      port: 8761
    
    eureka:
      instance:
        hostname: eureka-server
      client:
        register-with-eureka: false
        fetch-registry: false

主类添加@EnableEurekaServer注解:

package com.example.eureka;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication

@EnableEurekaServer

public class EurekaServerApplication {

public static void main(String[] args) {

SpringApplication.run(EurekaServerApplication.class, args);

}

}
  • User Service:创建一个 Spring Boot 项目,添加spring-cloud-starter-netflix-eureka-client、spring-boot-starter-web依赖,配置文件application.yml如下:
    server:
      port: 8081
    
    eureka:
      client:
        service-url:
          defaultZone: http://eureka-server:8761/eureka/

创建一个简单的控制器类UserController.java:

package com.example.user.controller;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class UserController {

@GetMapping("/user")

public String getUser() {

return "User Service: Hello, User!";

}

}

主类添加@EnableEurekaClient注解:

package com.example.user;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication

@EnableEurekaClient

public class UserServiceApplication {

public static void main(String[] args) {

SpringApplication.run(UserServiceApplication.class, args);

}

}
  • Order Service:创建一个 Spring Boot 项目,添加spring-cloud-starter-netflix-eureka-client、spring-boot-starter-web依赖,配置文件application.yml如下:
    server:
      port: 8082
    
    eureka:
      client:
        service-url:
          defaultZone: http://eureka-server:8761/eureka/

创建一个简单的控制器类OrderController.java,通过RestTemplate调用User Service的接口:

package com.example.order.controller;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.client.RestTemplate;

@RestController

public class OrderController {

@Autowired

private RestTemplate restTemplate;

@GetMapping("/order")

public String getOrder() {

String userInfo = restTemplate.getForObject("http://user-service/user", String.class);

return "Order Service: " + userInfo;

}

}

在主类中注入RestTemplate并添加@LoadBalanced注解:

package com.example.order;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import org.springframework.context.annotation.Bean;

import org.springframework.web.client.RestTemplate;

@SpringBootApplication

@EnableEurekaClient

public class OrderServiceApplication {

@Bean

@LoadBalanced

public RestTemplate restTemplate() {

return new RestTemplate();

}

public static void main(String[] args) {

SpringApplication.run(OrderServiceApplication.class, args);

}

}
  1. 编写 Dockerfile:为每个微服务项目编写Dockerfile,以User Service为例:
    # 使用官方的OpenJDK 11作为基础镜像
    
    FROM openjdk:11
    
    # 将本地的JAR包复制到容器中的/app目录下
    
    COPY target/user-service-0.0.1-SNAPSHOT.jar /app/
    
    # 设置工作目录为/app
    
    WORKDIR /app
    
    # 定义容器启动时执行的命令,运行JAR包
    
    CMD ["java", "-jar", "user-service-0.0.1-SNAPSHOT.jar"]
  2. 构建镜像:在每个微服务项目的根目录下执行docker build命令构建镜像,例如:
    docker build -t user-service:1.0.0.
  3. 使用 Docker Compose 编排微服务:在一个新的目录下创建docker-compose.yml文件,内容如下:
    version: '3'
    services:
      eureka-server:
        image: eureka-server:1.0.0
        ports:
          - "8761:8761"
      user-service:
        image: user-service:1.0.0
        depends_on:
          - eureka-server
      order-service:
        image: order-service:1.0.0
        depends_on:
          - eureka-server
          - user-service
        ports:
          - "8082:8082"
  • version: '3':指定 Docker Compose 文件的版本。
  • services:定义服务列表。
  • eureka-server:服务注册中心服务,指定镜像为eureka-server:1.0.0,并将容器的 8761 端口映射到宿主机的 8761 端口。
  • user-service:服务提供者服务,依赖于eureka-server,指定镜像为user-service:1.0.0。
  • order-service:服务消费者服务,依赖于eureka-server和user-service,指定镜像为order-service:1.0.0,并将容器的 8082 端口映射到宿主机的 8082 端口。
  1. 启动微服务:在docker-compose.yml文件所在目录下执行以下命令启动微服务:
    docker-compose up -d

-d参数表示以后台守护进程模式启动,启动后可以通过访问http://localhost:8761查看 Eureka Server 的注册信息,访问http://localhost:8082/order测试微服务之间的调用。

Docker 使用技巧与优化

镜像构建优化

  • 选择基础镜像:选择合适的基础镜像对于优化镜像大小和性能至关重要。优先选择官方提供的、经过优化的基础镜像,如openjdk:11-jdk-slim,相比完整的 JDK 镜像,-slim版本去除了不必要的组件,体积更小。对于一些对资源要求苛刻的场景,还可以考虑使用轻量级的 Linux 发行版作为基础镜像,如Alpine Linux。Alpine Linux基于musl libc和busybox,体积非常小,通常只有几 MB,能显著减小最终镜像的大小。例如,在构建一个简单的 Java Web 应用镜像时,如果使用openjdk:11-jdk作为基础镜像,镜像大小可能在几百 MB,而使用openjdk:11-jdk-alpine,镜像大小可以减小到几十 MB。
  • 减少镜像层数:每一个RUN、COPY、ADD指令都会创建一个新的镜像层,过多的镜像层会增加镜像的大小和构建时间。可以通过合并多个RUN指令来减少层数。比如,原本需要安装多个软件包并进行清理操作,若写成多个RUN指令:
    RUN apt-get update
    
    RUN apt-get install -y package1
    
    RUN apt-get install -y package2
    
    RUN rm -rf /var/lib/apt/lists/*

这样会创建 4 个镜像层。可以合并为一个RUN指令:

RUN apt-get update && apt-get install -y package1 package2 && rm -rf /var/lib/apt/lists/*

这样只创建一个镜像层,减小了镜像的复杂性和大小。

  • 利用.dockerignore 文件:.dockerignore文件用于指定在构建镜像时应该忽略的文件和目录,类似于.gitignore文件。在构建 Java 项目镜像时,target目录(存放编译后的文件)、.git目录(版本控制相关文件)以及一些日志文件、缓存文件等通常不需要被包含在镜像中。在项目根目录下创建.dockerignore文件,内容如下:
    target/
    
    .git/
    
    logs/
    
    *.log

这样在构建镜像时,Docker 会忽略这些文件和目录,避免将不必要的文件复制到镜像中,从而减小镜像的体积并提高构建速度 。

容器资源管理

在生产环境中,合理分配容器的资源(如 CPU、内存)是非常重要的,它可以确保容器在运行时不会因为资源不足而出现性能问题,也不会占用过多资源影响其他容器或宿主机的运行。

  • 设置容器 CPU 限制
  •      使用--cpus参数:可以通过--cpus参数来限制容器可以使用的 CPU 核心数。例如,如果希望限制容器只能使用 1.5 个 CPU 核心,可以在运行容器时使用以下命令:
    docker run --cpus="1.5" -d my-java-app:1.0.0
  • 使用--cpu-shares参数:--cpu-shares用于设置 CPU 的相对权重。Docker 会根据所有容器的cpu-shares值来分配 CPU 时间。例如,有两个容器container1和container2,container1的--cpu-shares设置为 200,container2的--cpu-shares设置为 100,那么在 CPU 资源竞争时,container1将获得大约两倍于container2的 CPU 时间。运行容器时设置--cpu-shares的命令如下:
    docker run --cpu-shares=200 -d my-java-app:1.0.0
  • 使用--cpuset-cpus参数:--cpuset-cpus可以指定容器可以使用的 CPU 核心。例如,--cpuset-cpus="0,1"表示容器只能使用第 0 个和第 1 个 CPU 核心,命令如下:
    docker run --cpuset-cpus="0,1" -d my-java-app:1.0.0
  • 设置容器内存限制
  •   使用-m--memory参数:通过-m或--memory参数可以设置容器的最大内存使用量。例如,限制容器使用 512MB 内存,可以使用以下命令:
    docker run -m 512m -d my-java-app:1.0.0
  • 使用--memory-swap参数:--memory-swap用于设置内存加交换空间的总限制。例如,设置容器的内存和交换空间总和为 1GB,可以使用以下命令:
    docker run -m 512m --memory-swap=1g -d my-java-app:1.0.0
  • 使用--memory-reservation参数:--memory-reservation设置内存的软限制,它表示容器尽量使用的内存量,但在系统内存紧张时,容器可以使用超过这个限制的内存,直到达到--memory设置的硬限制。例如,设置内存软限制为 256MB,硬限制为 512MB,可以使用以下命令:
    docker run -m 512m --memory-reservation=256m -d my-java-app:1.0.0

通过合理设置容器的 CPU 和内存限制,可以有效提高系统的稳定性和性能,确保各个容器在有限的资源条件下能够正常运行 。

常见问题与解决方法

在使用 Docker 的过程中,难免会遇到一些问题。以下是一些常见问题及解决方法:

  • 镜像拉取失败
  •     问题描述:使用docker pull命令拉取镜像时,提示网络超时、连接被拒绝或镜像未找到等错误信息。
  •     排查思路:首先检查网络连接是否正常,可以通过ping命令测试能否访问 Docker Hub 或其他镜像仓库的域名;确认输入的镜像名称和标签是否正确;查看 Docker 服务是否正在运行;检查是否达到 Docker Hub 的速率限制(免费账户有拉取请求的速率限制)。
  •     解决方案:如果是网络问题,可以尝试更换网络环境,或使用国内的镜像源,如阿里云、网易云等;若镜像名称错误,仔细核对正确的镜像名称和标签;若 Docker 服务未运行,使用sudo systemctl start docker命令启动;若达到速率限制,等待一段时间或升级到付费账户。例如,拉取openjdk:11镜像失败时,先检查网络连接,若网络正常,可修改镜像源,在/etc/docker/daemon.json文件中添加国内镜像源地址:
    {
    
    "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
    
    }

然后重启 Docker 服务sudo systemctl restart docker,再重新拉取镜像docker pull openjdk:11。

  • 容器启动报错
    • 问题描述:使用docker run命令启动容器时,提示容器无法启动、端口冲突、权限不足等错误。
    • 排查思路:对于端口冲突问题,检查指定的端口是否被其他应用程序占用;权限不足问题,查看启动命令是否以管理员身份运行,或者检查容器内运行的程序是否需要特定权限;若容器无法启动,查看容器日志docker logs <容器ID或名称>获取更多错误信息。
    • 解决方案:如果是端口冲突,停止占用该端口的服务,或者在启动容器时指定其他未被占用的端口,如docker run -d -p 8081:8080 my-java-app:1.0.0;对于权限问题,以管理员身份运行启动命令,或者在 Dockerfile 中合理设置用户权限;若容器因其他原因无法启动,根据容器日志中的错误信息进行针对性解决,如缺少依赖包则在 Dockerfile 中添加安装依赖的命令。
  • 容器内应用无法访问外部服务
    • 问题描述:容器内的 Java 应用程序无法连接到外部的数据库、消息队列等服务。
    • 排查思路:检查容器的网络设置是否正确,如是否配置了正确的网络模式;确认外部服务的地址和端口是否可访问,可在容器内使用ping命令测试网络连通性,使用telnet命令测试端口是否开放;检查防火墙设置,确保容器能够访问外部服务的端口。
    • 解决方案:如果是网络模式问题,可尝试更换网络模式,如从默认的bridge模式改为host模式(docker run -d --network=host my-java-app:1.0.0),以使用宿主机的网络;若外部服务地址或端口不可访问,检查服务的配置和运行状态;若防火墙阻止了访问,可在防火墙上开放相应的端口,或者关闭防火墙(仅在测试环境中建议关闭,生产环境需谨慎操作)。
  • 镜像构建失败
    • 问题描述:使用docker build命令构建镜像时,提示语法错误、文件找不到、依赖安装失败等问题。
    • 排查思路:仔细检查 Dockerfile 的语法是否正确,特别是RUN、COPY、ADD等指令的使用;确认 Dockerfile 中指定的文件和路径是否存在于构建上下文中;若依赖安装失败,查看安装命令的输出信息,可能是源地址不可用或依赖包名称错误。
    • 解决方案:如果是 Dockerfile 语法错误,根据错误提示进行修正;文件找不到问题,确保文件在正确的位置,并且在构建命令中指定了正确的上下文路径;依赖安装失败时,更换源地址,如在安装 Java 依赖时,将apt-get源更换为国内源,在 Dockerfile 中添加:
      RUN sed -i 's/http://archive.ubuntu.com/http://mirrors.aliyun.com/g' /etc/apt/sources.list
      
      RUN apt-get update

然后重新构建镜像。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值