天池Docker学习赛笔记

容器的基本概念

什么是容器?

容器就是一个视图隔离、资源可限制、独立文件系统的进程集合。所谓“视图隔离”就是能够看到部分进程以及具有独立的主机名等;控制资源使用率则是可以对于内存大小以及 CPU 使用个数等进行限制。容器就是一个进程集合,它将系统的其他资源隔离开来,具有自己独立的资源视图。

容器具有一个独立的文件系统,因为使用的是系统的资源,所以在独立的文件系统内不需要具备内核相关的代码或者工具,我们只需要提供容器所需的二进制文件、配置文件以及依赖即可。只要容器运行时所需的文件集合都能够具备,那么这个容器就能够运行起来。

如何为进程提供一个独立的运行环境呢?

  • 针对不同进程使用同一个文件系统所造成的问题而言,Linux 和 Unix 操作系统可以通过 chroot 系统调用将子目录变成根目录,达到视图级别的隔离;进程在 chroot 的帮助下可以具有独立的文件系统,对于这样的文件系统进行增删改查不会影响到其他进程;
  • 因为进程之间相互可见并且可以相互通信,使用 Namespace 技术来实现进程在资源的视图上进行隔离。在 chroot 和 Namespace 的帮助下,进程就能够运行在一个独立的环境下了;
  • 但在独立的环境下,进程所使用的还是同一个操作系统的资源,一些进程可能会侵蚀掉整个系统的资源。为了减少进程彼此之间的影响,可以通过 Cgroup 来限制其资源使用率,设置其能够使用的 CPU 以及内存量。

什么是镜像?

我们将容器运行时所需要的所有的文件集合称之为容器镜像。

docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。

image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。举例来说,你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。

那么,一般都是通过什么样的方式来构建镜像的呢?通常情况下,我们会采用 Dockerfile 来构建镜像,这是因为 Dockerfile 提供了非常便利的语法糖,能够帮助我们很好地描述构建的每个步骤。当然,每个构建步骤都会对已有的文件系统进行操作,这样就会带来文件系统内容的变化,我们将这些变化称之为 changeset。当我们把构建步骤所产生的变化依次作用到一个空文件夹上,就能够得到一个完整的镜像。

changeset 的分层以及复用特点能够带来几点优势

第一,能够提高分发效率,简单试想一下,对于大的镜像而言,如果将其拆分成各个小块就能够提高镜像的分发效率,这是因为镜像拆分之后就可以并行下载这些数据;

第二,因为这些数据是相互共享的,也就意味着当本地存储上包含了一些数据的时候,只需要下载本地没有的数据即可,举个简单的例子就是 golang 镜像是基于 alpine 镜像进行构建的,当本地已经具有了 alpine 镜像之后,在下载 golang 镜像的时候只需要下载本地 alpine 镜像中没有的部分即可;

第三,因为镜像数据是共享的,因此可以节约大量的磁盘空间,简单设想一下,当本地存储具有了 alpine 镜像和 golang 镜像,在没有复用的能力之前,alpine 镜像具有 5M 大小,golang 镜像有 300M 大小,因此就会占用 305M 空间;而当具有了复用能力之后,只需要 300M 空间即可。

容器的使用

本部分主要围绕学习赛所用到的命令进行讲解从而学习docker的使用流程

构建Docker镜像

在项目的根目录下,新建一个文本文件Dockerfile,其中包含一组指令来告诉 Docker 如何构建我们的镜像。Docker会根据该文件生成二进制的 image 文件。

# 指定基础镜像
FROM registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2
# 把当前文件夹里的文件拷贝到镜像的根目录下
ADD . /
# 指定接下来的工作路径为/(根目录)
WORKDIR /
# 指定镜像启动后要执行的命令
CMD ["sh","run.sh"]

构建启动后要执行的run.sh

run.sh内容

java -jar XX.jar

编写业务部分

这部分就是我们真正的项目内容,按照赛题来说,其实业务代码逻辑很简单,生成json就可以了,镜像下面也已经给好了csv文件,json这块我用了fastjson,打jar包的时候把依赖一起打进去就可以啦。

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TC {
    public static void main(String[] args) {
        List<Integer> res = new ArrayList<>();
        int sum = 0;
        try (BufferedReader file = new BufferedReader(new InputStreamReader(new FileInputStream("/tcdata/num_list.csv"), "UTF-8"))) {
            String record;
            while ((record = file.readLine()) != null) {
                res.add(Integer.parseInt(record));
                sum += Integer.parseInt(record);
            }
        } catch (Exception e) {

        }
        Collections.sort(res,Collections.reverseOrder());
        JSONObject jsonObject = new JSONObject();
        JSONArray jsonArray = new JSONArray();
        for(int i = 0;i < 10;i++){
            if(i >= res.size())
                break;
            jsonArray.add(res.get(i));
        }
        jsonObject.put("Q1","Hello world");
        jsonObject.put("Q2",sum);
        jsonObject.put("Q3",jsonArray);

        String sourceString = jsonObject.toJSONString();	//待写入字符串
        byte[] sourceByte = sourceString.getBytes();
        if(null != sourceByte) {
            try {
                File file = new File("result.json");        //文件路径(路径+文件名)
                if (!file.exists()) {    //文件不存在则创建文件,先创建目录
                    file.createNewFile();
                }
                FileOutputStream outStream = new FileOutputStream(file);    //文件输出流用于将数据写入文件
                outStream.write(sourceByte);
                outStream.close();    //关闭文件输出流
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

本地测试

镜像抓取

镜像抓取命令

docker image pull library/hello-world

上面代码中,docker image pull是抓取 image 文件的命令。library/hello-world是 image 文件在仓库里面的位置,其中library是 image 文件所在的组,hello-world是 image 文件的名字。

Base Docker Image List中给出了主办方为我们提供的镜像列表,所以我们通过以下指令获取java镜像

docker pull registry.cn-shanghai.aliyuncs.com/tcc-public/java:jdk_13.0.2

本地构建

docker build -t registry.cn-shanghai.aliyuncs.com/wx_namespace/wx_namespace_learning:2 .

本地运行测试

这块我还有一点疑问,就是我docker run container后进入到容器中查看并没有发现/tcdata/num_list.csv文件,可是提交却能够通过,这块还不知道是为什么?

回答:跟群友交流得知,这个文件并不在提供给我们的镜像中,而是在评测环境中。

docker run -v /data:/tcdata your_image sh run.sh

可以通过 -v 把运行环境的某个路径映射成镜像里的/tcdata。比如这里我把我主机的/data目录映射成 /tcdata目录。
有点类似windows上面的映射网络驱动器。

sudo docker run –it registry.cn-shanghai.aliyuncs.com/wx_namespace/wx_namespace_learning:2 /bin/bash

-it参数:容器的 Shell 映射到当前的 Shell,然后你在本机窗口输入的命令,就会传入容器。

/bin/bash:容器启动以后,内部第一个执行的命令。这里是启动 Bash,保证用户可以使用 Shell。

我们可以通过run指令查看运行结果,进行本地测试。

构建镜像并推送

命令行推送

推送的话说起来其实很简单

docker push registry.cn-shenzhen.aliyuncs.com/test_for_tianchi/test_for_tianchi_submit:1.0

但是由于比赛推荐我们使用私有仓库,所以要先登录下阿里云账号

sudo docker login --username=XXX registry.cn-shanghai.aliyuncs.com

IDE + Cloud Toolkit方法

IDE + Cloud Toolkit
这种方式推送到镜像仓库比较便捷,具体可以见链接

提交运行

推送到镜像仓库后,在竞赛界面提交运行即可。

posted @ 2020-04-27 12:10  wunsiang  阅读(236)  评论(0编辑  收藏  举报