我们没有必要从头开始构建一个docker镜像完善开发系统,而是在一个相对完善的docker镜像的基础上加以扩展,达到我们的目的。
从doker hub获取原始镜像
执行
$ sudo apt install docker.io
$ sudo docker pull gcc
下载后查看当前系统的docker镜像列表:
进入docker:
首先我们看一下系统当前是没有活动的docker容器的:
此时,我们创建一个,并且将主机的home目录映射为容器的/data/目录
sudo docker run -it -v ~/:/data gcc /bin/bash
start up command also can be:
sudo docker run -it -v ~/:/data $docker_image_id /bin/bash
a record entry installed after each running session
the CONTAINER ID and NAMES item are dynamic allocated each running session.
below two commands are used to manange the running session.
sudo docker stop 94ad6ab47180
sudo docker start 94ad6ab47180
if you wnat to inteactive with the docker,you can add -i option after above command
sudo docker start 94ad6ab4718 -i
同一个内核:
在docker中获取到的内核信息和在HOST主机中获取到的内核信息相同,说明docker用的是主机的内核。
构建melis系统:
我们一步一步来,首先我们把系统放在HOST共享目录中,通过容器去编译,
a deep usage about docker please refer:
基于Docker环境的YOLCAT语意分割模型实验环境搭建_papaofdoudou的博客-优快云博客_yolcat
other options on docker:
sudo docker exec 866a9a9a3221 ps -ef
above command just get the pid from the view of docker inside,but how to get the realy pid from the host? you can get use below commands:
sudo docker container top 866a9a9a3221
we can view the heriarchy of process by command;
pstree -p -H 308334 #308334 is a.out PID
sudo docker top serene_wu
see the log from the view of host
docker exec -d serene_wu sleep 2000
sudo docker logs serene_wu|more
docker related process
related is dockerd, containerd, containerd-shim
namespace of containerd-shim(305281)─┬─bash(305302)───a.out(308334)
containerd is in the same namespace with hosts init, and a.out in docker is in the same name space with the docker bash.
how to get the current namespace of process?
how to create a namespace in helloworld?
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#define STACK_SIZE (1024 * 1024)
int idle(void *args)
{
printf("I'm child process, and my pid is: %d\n", getpid());
for (;;) {
sleep(1);
}
return 0;
}
pid_t clone_wrapper(int (*func)(void *), int flag, void *args)
{
char *stack, *stack_top;
stack = (char *)malloc(STACK_SIZE);
if (stack == NULL) {
printf("alloc stack for child failed!\n");
return -1;
}
stack_top = stack + STACK_SIZE; /* Assume stack grows downward */
return clone(func, stack_top, flag , args);
}
char *get_pid_ns(int pid)
{
char bytes[32];
sprintf(bytes, "/proc/%d/ns/pid", pid);
return strdup(bytes);
}
int main(void)
{
pid_t childs[2];
char *ns_file;
int fd;
printf("I'm parent, and my pid is: %d\n", getpid());
childs[0] = clone_wrapper(idle, CLONE_NEWPID, NULL);
if (childs[0] == -1) {
printf("error: create child thread failed!\n");
return -1;
}
printf("first child's pid is: %d\n", childs[0]);
ns_file = get_pid_ns(childs[0]);
printf("%s line %d, nsfile %s.\n", __func__, __LINE__, ns_file);
if (!ns_file) {
printf("get child pid ns failed!\n");
return -1;
}
fd = open(ns_file, O_RDONLY);
if (fd == -1) {
printf("open child pid ns failed!\n");
return -1;
}
if (setns(fd, 0) == -1) {
printf("set ns failed!\n");
return -1;
}
printf("I'm parent, and my pid is: %d\n", getpid());
childs[1] = clone_wrapper(idle, 0, NULL);
if (childs[1] == -1) {
printf("error: create child thread failed!\n");
return -1;
}
printf("second child's pid is: %d\n", childs[1]);
sleep(3);
kill(childs[0], SIGTERM);
kill(childs[1], SIGTERM);
waitpid(childs[0], NULL, 0);
waitpid(childs[1], NULL, 0);
return 0;
}
设备映射
使用--device参数进行设备映射,使用-v(volume)参数进行目录映射,这样,就可以在DOCKER内部访问HOST主机上的设备了。
sudo docker run -it --device /dev/miscdriver -v /home/zlcao/misc/miscdrv:/data gcc
启动一个容器:
$ sudo docker run -it --name zilong --device /dev/hidraw0 -v /home/zlcao/riscv:/doc --net=host gcc bash
查看docker启动配置:
$ docker inspect zilong($container id)
注意启动容器时,一定要加上bash选项,否则后续docker start/docker attach将会失败。
docker镜像和docker容器的关系
-
Docker 镜像(Docker Image): 镜像是一个只读的文件系统快照,它包含了一个完整的文件系统,其中包括应用程序、库、环境变量和配置文件等。镜像可以看作是应用程序的打包和分发方式,它定义了一个容器运行时所需的一切内容。镜像通常是静态的,不可修改的。
-
Docker 容器(Docker Container): 容器是从镜像创建的运行实例。容器是一个独立的环境,包括应用程序和其依赖项,以及操作系统的部分,但容器不包括整个操作系统。容器是可运行的,可以启动、停止、暂停、删除和交互。容器在创建时是可变的,可以根据需要进行修改,但不会影响底层镜像。
关系:
-
镜像是容器的基础。容器是根据镜像创建的,每个容器都基于一个特定的镜像运行。一个镜像可以用来创建多个容器实例。
-
镜像是静态的,通常不会发生改变,而容器是动态的,可以启动、停止、修改和删除。多个容器可以同时运行相同的镜像,每个容器之间是独立的、隔离的环境。
-
容器在运行时会引用镜像,并在其基础上创建一个可读写的文件系统层,使其成为一个运行时实例。容器的状态和文件系统的更改可以在容器之间独立保存,不会影响其他容器或镜像。
总之,Docker 镜像是静态的、不可变的模板,用于创建 Docker 容器的运行时实例。容器是可运行、可修改的实体,它们基于镜像运行并且可以在其中托管应用程序和服务。这种分离和隔离的机制使得 Docker 成为一种强大的容器化技术,用于构建、部署和管理应用程序。
可以将 Docker 镜像和容器的关系比喻为“食谱”和“菜肴”的关系:
-
Docker 镜像(食谱): Docker 镜像就像是一份食谱,其中包含了准备一道菜所需的所有信息,包括食材、调料、烹饪步骤等。这份食谱是静态的,不会改变,只是一份指南,告诉您如何准备一道特定的菜。
-
Docker 容器(菜肴): Docker 容器就像是根据食谱准备的实际菜肴。容器是动态的,它是根据特定的食谱(镜像)创建的,可以启动、停止、修改和删除。每个容器实例都是独立的,就像每份菜肴都是在特定时刻根据食谱准备的。
类比的关键点:
- 食谱(镜像)是不变的,不会随着菜肴(容器)的制作而改变。
- 菜肴(容器)是可变的,可以根据需要进行调整和修改。
- 多个菜肴可以使用相同的食谱(镜像)准备,而且每个菜肴都是独立的、隔离的。
这个比喻有助于理解 Docker 镜像和容器之间的关系,镜像是创建容器的基础,容器是实际运行和修改的实体。
在镜像的所有容器实例没有被删除干净时,是不能删除镜像的,如下图:
查看进程在宿主机或者DOCKER环境下的PID
sudo docker inspect -f '{{.State.Pid}}' zilong
sudo docker exec -it zilong ps aux
sudo docker top zilong
将容器保存为镜像:
$ sudo docker commit zilong zilong_images:v1.0
$ sudo docker save -o zilong_images.tar.bz2 zilong_images:v1.0
装载保存的镜像,之后就可以像其他镜像一样访问了:
sudo docker load --input zilong_images.tar.bz2
查看创建信息-共享目录设置
用如下命令查看配置清单中的Mounts设置:
$ sudo docker inspect 8ecfddee660f
docker环境下查看挂载信息,是看不到HOST机端具体的源目录的,只会显示其所在的设备:
Reference
理解Docker容器的进程管理 - ilinux_one - 博客园
Docker基础_docker exec bash_米花町的小侦探的博客-优快云博客
结束!