Docker-从入门到实践

发布于:2025-04-01 ⋅ 阅读:(13) ⋅ 点赞:(0)

其实就是对进程的封装,使得它与其他进程独立,并且独立于宿主,也称为容器

Docker是对容器的封装

那他与传统的虚拟机有什么区别呢?

传统虚拟需要虚拟出一套硬件,在其上面运行一个完整的操作系统,在这个系统上运行所需应用进程;而容器内的应用程序直接运行在宿主的内核,容器内没有直接点内核,也没有硬件虚拟。所以容器要比传统的虚拟机更加轻便。

那它有什么优势呢?

高效的利用系统的资源

快速的启动时间

一致的运行环境

持续交付和部署

轻松的迁移、维护和扩展

三个要素是啥?

镜像、容器、仓库

一、Docker概述

1.1 Docker 为什么出现?

  • 解决环境差异问题:开发、测试、生产环境不一致,导致应用部署困难。

  • 提高资源利用率:传统虚拟机资源占用大,Docker容器更轻量,能更高效地利用硬件资源。

1.2 Docker历史

  • 2013年,Docker项目启动。

  • 2014年,Docker 1.0版本发布,标志着Docker技术的成熟。

1.3 能做什么

  • 应用打包:将应用及其依赖打包成一个容器,确保在任何环境下都能正常运行。

  • 环境隔离:为每个应用提供独立的运行环境,避免依赖冲突。

  • 快速部署:容器启动迅速,能快速部署应用。

  • 持续集成与交付:与CI/CD流程结合,实现自动化测试和部署。

二、Docker安装

2.1 基本组成

  • Docker客户端:用户通过命令行工具与Docker守护进程通信。

  • Docker守护进程:负责构建、运行和管理容器。

  • Docker镜像:只读的模板,包含应用程序及其依赖。

  • Docker容器:镜像的运行实例,提供隔离的运行环境。

  • Docker仓库:存储和管理Docker镜像的地方。

2.2 安装Docker

  • Linux:使用包管理工具安装,如aptyum

  • Windows:安装Docker Desktop for Windows。

  • Mac:安装Docker Desktop for Mac。

2.3 阿里云镜像加速

  • 配置镜像加速可以提高镜像下载速度,特别是在国内网络环境下。

  • 配置方法:在Docker守护进程配置文件中添加镜像加速地址。

2.4 回顾hello-world流程

  • 拉取hello-world镜像:docker pull hello-world

  • 运行容器:docker run hello-world

2.5 底层原理

  • Docker是怎么工作的?

    • Docker利用Linux内核的Cgroups和NameSpace技术,对进程进行封装隔离。

    • 容器共享宿主机的操作系统内核,但彼此隔离。

  • Docker为什么比VM(虚拟机)快?

    • 虚拟机需要完整的操作系统,占用大量资源。

    • Docker容器共享宿主机的操作系统,资源占用少,启动速度快。

三、Docker的常用命令

3.1 帮助命令

  • docker --help:查看所有可用命令。

3.2 镜像命令

  • docker images:列出本地镜像。

  • docker search <镜像名>:在Docker Hub搜索镜像。

  • docker pull <镜像名>:拉取镜像。

  • docker rmi <镜像ID>:删除镜像。

3.3 容器命令

  • docker run <镜像名>:创建并运行容器。

  • docker ps:列出正在运行的容器。

  • docker ps -a:列出所有容器(包括停止的)。

  • docker stop <容器名>:停止容器。

  • docker start <容器名>:启动容器。

  • docker rm <容器名>:删除容器。

  • docker exec -it <容器名> /bin/bash:进入容器。

3.4 其他命令

  • docker logs <容器名>:查看容器日志。

  • docker cp <容器名>:<路径> <本地路径>:从容器复制文件到主机。

  • docker inspect <容器名>:查看容器详细信息。

四、Docker镜像

4.1 镜像是什么

  • 镜像是一个只读的模板,包含应用程序及其依赖。

  • 镜像由多层文件系统组成,每层代表一个文件系统的变更。

4.2 镜像加速原理

  • UnionFS(联合文件系统):允许多个文件系统(层)叠加在一起,形成一个统一的文件系统视图。

  • Docker 镜像加载原型:镜像的每一层都是只读的,当容器启动时,Docker会在镜像顶部添加一个可写的层,用于存储容器运行时的变更。

4.3 分层理解

  • 镜像的分层结构使得镜像共享和复用更加高效。

  • 多个容器可以共享同一镜像的底层,减少存储空间。

4.4 commit镜像

  • docker commit <容器名> <新镜像名>:将容器的更改提交为新的镜像。

五、Docker网络

5.1 网络类型

  • Bridge模式:默认网络,容器通过docker0网卡连接到宿主机。

  • Host模式:容器直接使用宿主机的网络栈,没有网络隔离。

  • Overlay模式:用于多宿主机的容器网络通信。

  • None模式:容器没有网络。

5.2 网络命令

  • docker network create <网络名>:创建自定义网络。

  • docker network ls:列出所有网络。

  • docker network rm <网络名>:删除网络。

  • docker network connect <网络名> <容器名>:将容器连接到网络。

  • docker network disconnect <网络名> <容器名>:将容器从网络断开。

六、Docker Compose

6.1 作用

  • Docker Compose用于定义和管理多容器应用,通过docker-compose.yml文件配置服务、网络和卷。

6.2 常用命令

  • docker-compose up:创建并启动所有服务。

  • docker-compose down:停止并删除所有服务、网络和卷。

  • docker-compose ps:列出所有服务的状态。

七、Docker实际应用案例

7.1 运行Nginx服务

bash复制

docker run -d -p 80:80 --name mynginx nginx

7.2 搭建Redis主从同步集群

bash复制

# 主节点
docker run -d -p 6379:6379 \
-v /app/rd1:/bitnami/redis/data \
-e REDIS_REPLICATION_MODE=master \
-e REDIS_PASSWORD=123456 \
--network mynet --name redis01 \
bitnami/redis

# 从节点
docker run -d -p 6380:6379 \
-v /app/rd2:/bitnami/redis/data \
-e REDIS_REPLICATION_MODE=slave \
-e REDIS_MASTER_HOST=redis01 \
-e REDIS_MASTER_PORT_NUMBER=6379 \
-e REDIS_MASTER_PASSWORD=123456 \
-e REDIS_PASSWORD=123456 \
--network mynet --name redis02 \
bitnami/redis

八、Docker在Java开发中的应用

8.1 部署Java应用

  • 将Java应用打包成Docker镜像,便于在不同环境中部署。

  • 使用Dockerfile定义Java应用的运行环境和启动命令。

8.2 示例:部署Spring Boot应用

dockerfile复制

# 使用官方Java镜像作为基础镜像
FROM openjdk:11-jre-slim

# 设置工作目录
WORKDIR /app

# 复制应用JAR文件到容器
COPY target/myapp.jar /app/myapp.jar

# 暴露应用端口
EXPOSE 8080

# 启动应用
CMD ["java", "-jar", "myapp.jar"]

通过以上内容的学习,你可以快速掌握Docker的基础知识和实际应用,为Java开发面试做好准备。

九、Docker在Java开发中的应用

一、基础概念

  • Docker:Docker是一个开源的平台,用于开发、部署和运行应用,可通过容器轻松打包应用及其依赖。

  • 容器:容器是一个标准的软件单元,它将代码及其所有依赖打包在一起,使Java应用在几乎任何计算环境中都能快速、可靠地运行。

  • 镜像:镜像是一个轻量级、独立、可执行的打包格式,包含了运行应用所需的所有内容,包括Java运行环境、代码、库。

二、Java应用的Docker容器化

2.1 Dockerfile 编写

要容器化一个Java应用,首先需要编写一个 Dockerfile,它定义了如何构建Docker镜像。以下是一个简单的 Dockerfile 示例,用于Java应用:

dockerfile复制

# 使用OpenJDK基础镜像
FROM openjdk:11-jre-slim

# 设置工作目录
WORKDIR /app

# 复制应用Jar文件到容器
COPY target/my-java-app.jar /app/my-java-app.jar

# 暴露应用端口
EXPOSE 8080

# 执行Java应用命令
CMD ["java", "-jar", "/app/my-java-app.jar"]

2.2 构建 Docker 镜像

Dockerfile 编写完成后,可以使用Docker命令行来构建镜像:

bash复制

docker build -t my-java-app .

此命令会将当前目录下的 Dockerfile 构建成一个名为 my-java-app 的Docker镜像。

2.3 运行 Docker 容器

构建好镜像后,接下来的步骤是运行容器:

bash复制

docker run -d -p 8080:8080 --name my-running-app my-java-app

该命令通过Docker镜像启动一个容器,并将8080端口映射到主机。

三、常见实践

3.1 使用Multi-stage构建

Multi-stage构建允许我们在一个 Dockerfile 中使用多个 FROM 命令,从而简化镜像并减少最终镜像的体积:

dockerfile复制

# 第一阶段:构建应用
FROM maven:3.8-openjdk-11 as builder
WORKDIR /build
COPY . .
RUN mvn clean package

# 第二阶段:创建运行时镜像
FROM openjdk:11-jre-slim
WORKDIR /app
COPY --from=builder /build/target/my-java-app.jar /app/my-java-app.jar
EXPOSE 8080
CMD ["java", "-jar", "/app/my-java-app.jar"]

3.2 环境变量配置

在容器化应用中,使用环境变量进行配置是一种推荐做法。可以在 Dockerfile 中或在 docker run 命令中设置:

dockerfile复制

ENV APP_ENV=production

运行时覆盖:

bash复制

docker run -e APP_ENV=staging -d -p 8080:8080 my-java-app

3.3 日志管理

为了有效管理日志,建议将Docker容器的日志输出到stdout和stderr,以便使用Docker自带的日志驱动进行管理。

四、最佳实践

4.1 优化镜像体积

  • 使用更小的基础镜像,比如 alpine

  • 清理不必要的构建依赖。

  • 使用 .dockerignore 文件忽略不需要添加到镜像中的文件。

4.2 安全性考虑

  • 使用非root用户运行应用。

  • 定期更新基础镜像以获取安全补丁:

dockerfile复制

# 创建用户并使用
RUN addgroup --system appgroup && adduser --system appuser --ingroup appgroup
USER appuser

4.3 版本管理

  • 为不同版本的应用打上不同标签: my-java-app:1.0.0

  • 使用CI/CD工具自动化构建和推送镜像。

五、Docker在Java开发中的应用案例

5.1 部署Spring Boot应用

假设我们有一个简单的Spring Boot应用,项目结构如下:

复制

my-spring-boot-app
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── myapp
│   │   │               ├── controller
│   │   │               │   └── HelloController.java
│   │   │               └── MyAppApplication.java
│   │   └── resources
│   │       ├── application.properties
│   │       └── static
│   │           └── index.html
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── myapp
│                       └── MyAppApplicationTests.java
├── pom.xml

其中HelloController.java代码如下:

java复制

package com.example.myapp.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
    @GetMapping("/")
    public String hello() {
        return "Hello, Docker with Spring Boot!";
    }
}

MyAppApplication.java代码如下:

java复制

package com.example.myapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyAppApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyAppApplication.class, args);
    }
}

1、创建 Dockerfile:在项目根目录下创建一个名为Dockerfile的文件,内容如下:

dockerfile复制

FROM openjdk:11
WORKDIR /app
COPY target/my-spring-boot-app-0.0.1-SNAPSHOT.jar /app/app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

2、构建项目:在项目根目录下执行mvn clean package命令,生成可执行的 JAR 包。 3、构建镜像:在项目根目录下执行以下命令构建镜像:

bash复制

sudo docker build -t my-spring-boot-app .

4、运行容器:构建镜像成功后,就可以运行容器了:

bash复制

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

5.2 多容器应用(以 Java Web 应用和 MySQL 为例)

1、添加依赖:在pom.xml文件中添加 MyBatis-Plus 和相关依赖:

xml复制

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>最新版本号</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

2、配置文件:在application.properties中添加数据库连接和 MyBatis-Plus 相关配置:

properties复制

spring.datasource.url=jdbc:mysql://mysql:3306/javadb?useSSL=false&characterEncoding=utf8
spring.datasource.username=javauser
spring.datasource.password=javapassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis-plus.mapper-locations=classpath:/mapper/*.xml
mybatis-plus.type-aliases-package=com.example.mywebapp.entity

3、代码实现

  • User.java实体类:

java复制

package com.example.mywebapp.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("users")
public class User {
    private Integer id;
    private String name;
}
  • UserMapper.java接口:

java复制

package com.example.mywebapp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mywebapp.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
  • IUserService.java接口:

java复制

package com.example.mywebapp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mywebapp.entity.User;
public interface IUserService extends IService<User> {
}
  • UserServiceImpl.java实现类:

java复制

package com.example.mywebapp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mywebapp.entity.User;
import com.example.mywebapp.mapper.UserMapper;
import com.example.mywebapp.service.IUserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}
  • UserController.java控制器:

java复制

package com.example.mywebapp.controller;
import com.example.mywebapp.entity.User;
import com.example.mywebapp.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/user")
    public User getUser(@RequestParam Integer id) {
        return userService.getById(id);
    }
}
  • MyBatisPlusConfig.java配置类(可选,用于自定义 MyBatis-Plus 配置):

java复制

package com.example.mywebapp.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.example.mywebapp.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

4、创建 Dockerfile:在项目根目录下创建一个名为Dockerfile的文件,内容如下:

dockerfile复制

FROM tomcat:9.0
WORKDIR /usr/local/tomcat/webapps
COPY target/my-java-web-app.war ROOT.war
EXPOSE 8080
CMD ["catalina.sh", "run"]

5、构建项目:在项目根目录下执行mvn clean package命令,生成可执行的 WAR 包。 6、构建镜像:在项目根目录下执行以下命令构建镜像:

bash复制

sudo docker build -t my-java-web-app .

7、运行容器:构建镜像成功后,就可以运行容器了:

bash复制

sudo docker run -d -p 8081:8080 --link my-mysql:mysql my-java-web-app

参数解释:

  • --link my-mysql:mysql:将 Java Web 应用容器与 MySQL 容器建立链接,my-mysql是 MySQL 容器的名称,mysql是链接别名,方便在 Java Web 应用中通过mysql来访问 MySQL 容器。

  • -p 8081:8080:将容器内部的 Tomcat 端口 8080 映射到主机的 8081 端口。

通过浏览器访问 http://localhost:8081/user?id=1,就可以看到根据数据库查询结果展示的用户信息页面,这两个容器之间通过网络进行通信,协同工作