基于Docker容器的,Jenkins、GitLab构建持续集成CI

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 一、场景: 开发者将代码提交(push)到GitLab后,GitLab通过Hook通知jenkins,jenkins自动从GitLab中获取项目最新的源码进行集成和发布。 二、准备: 基于Docker,创建一个私有GitLab的容器,创建一个jenkins的容器 三、步骤 1、构建Jenkins容器 Jenkins容器安装Jenkins的rpm包,Jenkins依赖 JDK,所以需要在Jenkins的容器中安装配置jdk,本人使用jdk1.8,同时需要Jenkins的容器调用maven的打包命令,所以也需要配置安装maven,本人使用maven 3.3.9。

** 开发者将代码提交(push)到GitLab后,GitLab通过Hook通知jenkins,jenkins自动从GitLab中获取项目最新的源码进行集成和发布。

基于Docker,创建一个私有GitLab的容器,创建一个jenkins的容器**

1. 构建私有的GitLab容器

https://about.gitlab.com/installation/#centos-7,直接安装gitlab,不借助docker

通过docker-compose的方式安装gitlab,docker-compose这个命令需要单独安装,docker-compose会对指定目录下的docker-compose.yml文件进行执行,这个文件会一次性启动所编辑的镜像,及所要用到的参数,官方提供的yml文件内容如下:

#Install docker-compose
 sudo curl -L https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
version: '2'

services:
  redis:
    restart: always
    image: sameersbn/redis:latest
    command:
    - --loglevel warning
    volumes:
    - /srv/docker/gitlab/redis:/var/lib/redis:Z   #文件的挂载点

  postgresql:
    restart: always
    image: sameersbn/postgresql:9.6-2
    volumes:
    - /srv/docker/gitlab/postgresql:/var/lib/postgresql:Z   #文件的挂载点
    environment:
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production
    - DB_EXTENSION=pg_trgm

  gitlab:
    restart: always
    image: sameersbn/gitlab:9.1.4
    depends_on:
    - redis
    - postgresql
    ports:
    - "10080:80"
    - "10022:22"
    volumes:
    - /srv/docker/gitlab/gitlab:/home/git/data:Z  #文件的挂载点
    environment:
    - DEBUG=false

    - DB_ADAPTER=postgresql
    - DB_HOST=postgresql
    - DB_PORT=5432
    - DB_USER=gitlab
    - DB_PASS=password
    - DB_NAME=gitlabhq_production

    - REDIS_HOST=redis
    - REDIS_PORT=6379

    - TZ=Asia/Kolkata
    - GITLAB_TIMEZONE=Kolkata

    - GITLAB_HTTPS=false
    - SSL_SELF_SIGNED=false

    - GITLAB_HOST=localhost
    - GITLAB_PORT=10080
    - GITLAB_SSH_PORT=10022
    - GITLAB_RELATIVE_URL_ROOT=
    - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string

    - GITLAB_ROOT_PASSWORD=
    - GITLAB_ROOT_EMAIL=

    - GITLAB_NOTIFY_ON_BROKEN_BUILDS=true
    - GITLAB_NOTIFY_PUSHER=false

    - GITLAB_EMAIL=notifications@example.com
    - GITLAB_EMAIL_REPLY_TO=noreply@example.com
    - GITLAB_INCOMING_EMAIL_ADDRESS=reply@example.com

    - GITLAB_BACKUP_SCHEDULE=daily
    - GITLAB_BACKUP_TIME=01:00

    - SMTP_ENABLED=false
    - SMTP_DOMAIN=www.example.com
    - SMTP_HOST=smtp.gmail.com
    - SMTP_PORT=587
    - SMTP_USER=mailer@example.com
    - SMTP_PASS=password
    - SMTP_STARTTLS=true
    - SMTP_AUTHENTICATION=login

    - IMAP_ENABLED=false
    - IMAP_HOST=imap.gmail.com
    - IMAP_PORT=993
    - IMAP_USER=mailer@example.com
    - IMAP_PASS=password
    - IMAP_SSL=true
    - IMAP_STARTTLS=false

    - OAUTH_ENABLED=false
    - OAUTH_AUTO_SIGN_IN_WITH_PROVIDER=
    - OAUTH_ALLOW_SSO=
    - OAUTH_BLOCK_AUTO_CREATED_USERS=true
    - OAUTH_AUTO_LINK_LDAP_USER=false
    - OAUTH_AUTO_LINK_SAML_USER=false
    - OAUTH_EXTERNAL_PROVIDERS=

    - OAUTH_CAS3_LABEL=cas3
    - OAUTH_CAS3_SERVER=
    - OAUTH_CAS3_DISABLE_SSL_VERIFICATION=false
    - OAUTH_CAS3_LOGIN_URL=/cas/login
    - OAUTH_CAS3_VALIDATE_URL=/cas/p3/serviceValidate
    - OAUTH_CAS3_LOGOUT_URL=/cas/logout

    - OAUTH_GOOGLE_API_KEY=
    - OAUTH_GOOGLE_APP_SECRET=
    - OAUTH_GOOGLE_RESTRICT_DOMAIN=

    - OAUTH_FACEBOOK_API_KEY=
    - OAUTH_FACEBOOK_APP_SECRET=

    - OAUTH_TWITTER_API_KEY=
    - OAUTH_TWITTER_APP_SECRET=

    - OAUTH_GITHUB_API_KEY=
    - OAUTH_GITHUB_APP_SECRET=
    - OAUTH_GITHUB_URL=
    - OAUTH_GITHUB_VERIFY_SSL=

    - OAUTH_GITLAB_API_KEY=
    - OAUTH_GITLAB_APP_SECRET=

    - OAUTH_BITBUCKET_API_KEY=
    - OAUTH_BITBUCKET_APP_SECRET=

    - OAUTH_SAML_ASSERTION_CONSUMER_SERVICE_URL=
    - OAUTH_SAML_IDP_CERT_FINGERPRINT=
    - OAUTH_SAML_IDP_SSO_TARGET_URL=
    - OAUTH_SAML_ISSUER=
    - OAUTH_SAML_LABEL="Our SAML Provider"
    - OAUTH_SAML_NAME_IDENTIFIER_FORMAT=urn:oasis:names:tc:SAML:2.0:nameid-format:transient
    - OAUTH_SAML_GROUPS_ATTRIBUTE=
    - OAUTH_SAML_EXTERNAL_GROUPS=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_EMAIL=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_FIRST_NAME=
    - OAUTH_SAML_ATTRIBUTE_STATEMENTS_LAST_NAME=

    - OAUTH_CROWD_SERVER_URL=
    - OAUTH_CROWD_APP_NAME=
    - OAUTH_CROWD_APP_PASSWORD=

    - OAUTH_AUTH0_CLIENT_ID=
    - OAUTH_AUTH0_CLIENT_SECRET=
    - OAUTH_AUTH0_DOMAIN=

    - OAUTH_AZURE_API_KEY=
    - OAUTH_AZURE_API_SECRET=
    - OAUTH_AZURE_TENANT_ID=

在docker-compose.yml文件所在目录下,执行docker-compose up命令(docker-compose命令需要安装),如果之前没有下载过GitLab的镜像会自动下载,如果下载过就直接启动已有的容器。

这里会在docker创建一个新的网桥,gitlab所需要的gitlab容器和redis容器及postgresql容器都在这个网桥指定的网段内,可以通过docker network ls查看.

网桥的名称通常为你yml文件所在目录名称的小写加上下划线default,例如mygitlab_default。这个很有用,因为如果你想要容器内部互联,就需要指定所要连接的容器在一个网段内,例如jenkins容器如果想内部连接gitlab容器,就得都在mygitlab_default这个网桥提供的网段内,Docker默认会为容器指定在docker0这个网段内的一个ip,通常会是172.17.. 我的gitlab默认在172.18,所以需要在接下来创建jenkins容器并启动时,指定到18这个网段内,当然你想通过宿主机的ip和端口也是可以的

执行完成之后,gitlab容器的80端口绑定在了宿主机的10080端口,同时gitlab容器的22端口(ssh)绑定在宿主机10022端口。可以通过访问localhost:10080来访问私有仓库

2. 构建Jenkins容器

Jenkins容器安装Jenkins的rpm包,Jenkins依赖 JDK,所以需要在Jenkins的容器中安装配置jdk,本人使用jdk1.8,同时需要Jenkins的容器调用maven的打包命令,所以也需要配置安装maven,本人使用maven 3.3.9。

a.通过Dockerfile构建一个jenkins容器,基于centos7的镜像。



这里不推荐将一个基础镜像一次性打包成完整的应用镜像,建议构建三层镜像模型。
所谓三层镜像就是,基础镜像,中间件镜像,应用镜像。例如我要构建一个Jenkins 的镜像,打包一个基于Centos7 和一些常用工具的镜像就是基础镜像,例如叫Centos7-base。然后这里Jenkins依赖Java和Maven,所以在基于Centos7-base的基础上安装配置java及maven后,再打包的镜像为中间件镜像,例如叫Centos7-jdk8-mvn3,这层中间件的镜像我们为来的复用会很高,以后只要有基于java1.8和maven3的,就可以直接使用这个镜像进行构建。最后我们再在Centos7-jdk8-mvn3的基础上安装配置jenkins,最后打包运用在生产环境。

b.构建基础镜像,整合jdk及mvn。配置PATH ,安装所需要的工具,Dockerfile如下:

#base on centos 7 image

FROM daocloud.io/centos:7
MAINTAINER hoewon
LABEL JDK \ 1.8

COPY jdk1.8 /usr/local/jdk1.8/  \
             maven /usr/local/maven/

RUN yum install -y openssh-server openssh-clients git 

RUN yum install -y iproute  net-tools

ENV JAVA_HOME /usr/local/jdk1.8


ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 8080


ENTRYPOINT /bin/bash
将要复制进镜像里的jdk和maven文件放到与Dockerfile相同的目录下

执行命令打包镜像

#最后 . 是当前目录的意思,不可省略,或自定义Dockerfile所在目录

docker build -t repo/name:tag  .  

#成功后查看本地镜像

docker images 

c.通过基础镜像安装jenkins,也是通过Dockerfile

#A jenkins 2.7.4 on centos 7 image
#基于刚才做好的基础镜像
FROM 127.0.0.1:5000/env/centos7-jdk8-mvn:1.3
MAINTAINER hoewon
LABEL JDK1.8 \ Jenkins-2.7.4
#复制jenkins rpm至镜像
COPY jenkins.rpm /usr/local/

#创建jenkins用户,并更改密码

RUN useradd jenkins && echo "jenkins password"  > passwd jenkins --stdin

#安装jenkins

RUN rpm -ivh /usr/local/jenkins.rpm

#更改jenkins安装文件的所有者

RUN rpm -ql jenkins | xargs chown -R jenkins:jenkins

#创建jenkins日志文件

RUN touch /usr/lib/jenkins/jenkins-logs 

#更改日志文件所有者

RUN chown jenkins:jenkins /usr/lib/jenkins/jenkins-logs

#曝光8080端口

EXPOSE 8080

#启动容器时使用jenkins用户

USER jenkins

#定义用户空间为工作空间

WORKDIR /home/jenkins

#启动容器时启动jenkins

ENTRYPOINT java -jar /usr/lib/jenkins/jenkins.war &> /usr/lib/jenkins/jenkins-logs

d.运行jenkins容器,这里需要将container的网络设置跟GtiLab同网络的环境下,同时我们希望jenkins容器在用maven打包之后,在调用docker惊醒封装镜像,然后推送镜像至私有的镜像仓库,所以我们把宿主机的/usr/bin/docker 和/run/docker.sock 和所依赖的共享库文件,在启动容器时一并挂载至容器内部。

# --net 指定docker的网桥
 docker run -idt   --net mygitlab_default --name jenkins_c -p 8888:8080 -v /usr/lib64/libltdl.so.7:/usr/lib64/libltdl.so.7  -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker 127.0.0.1:5000/myjenkins:1.0 /bin/bash

e.容器启动后,8080端口被绑定到了宿主机的8888端口,访问localhost:8888来访问jenkins
首次登录jenkins会需要输入jenkins的超级管理员密码,这个密码在jenkins第一次启动的日志中,可以进入jenkins容器,查看运行日志,也可以根据页面提示,直接去jenkins的家目录下一个.jenkins/secrets/init…..的文件内查看密码。登录后注册一个用户,并在系统管理-管理插件下,安装GitLab的插件。第一次运行jenkins会让你选择安装插件,选择第一个推荐的安装后,在管理插件的可选插件tab下搜索Gitlab Plugin 和Gitlab Hook Plugin插件进行安装,然后重启jenkins

3.构建私有的Docker 镜像仓库
拉取一个docker 的镜像仓库镜像,并运行该容器,容器运行后会绑定宿主机5000端口,我个人用的是daocloud.io提供的镜像,这个镜像仓库需要注册。

docker run \
         -e SETTINGS_FLAVOR=s3 \
         -e AWS_BUCKET=acme-docker \
         -e STORAGE_PATH=/registry \
         -e AWS_KEY=AKIAHSHB43HS3J92MXZ \
         -e AWS_SECRET=xdDowwlK7TJajV1Y7EoOZrmuPEJlHYcNP2k4j49T \
         -e SEARCH_BACKEND=sqlalchemy \
         -p 5000:5000 \
         daocloud.io/registry

运行成功后,可以访问http://localhost:5000/v2/_catalog 来查看本地仓库信息

4.构建持续集成环境
万事具备,下面我们开始利用gitlab,jenkins,来构建持续集成环境。

a.在gitlab中创建一个项目,项目类为public,创建后会有如下提示,这些提示用来告诉你如何通过客户端下载项目,并提交项目

#Command line instructions 
#Git global setup
git config --global user.name "jenkins"
git config --global user.email "15561581025@163.com"
#Create a new repository
git clone ssh://git@localhost:10022/jenkins/demo.git
cd demo
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
#Existing folder
cd existing_folder
git init
git remote add origin ssh://git@localhost:10022/jenkins/demo.git
git add .
git commit
git push -u origin master
#Existing Git repository
cd existing_repo
git remote add origin ssh://git@localhost:10022/jenkins/demo.git
git push -u origin --all
git push -u origin --tags

b.进入jenkins容器,然后通过git客户端,拉取项目。在拉取之前,需要用使用ssh-keygen来生成当前jenkins用户在jenkins容器的公钥密钥,ssh-keygen需要安装openssh。

ssh-keygen – t rsa

可以一路回车,默认生成在jenkins用户的家目录下的一个.ssh的文件夹,将.ssh/id_rsa.pub的内容全部复制

c.登录gitlab,右上角下拉列表下选择setting,然后在主页面有一个SSH Keys的tab页,将你刚才复制的公钥内容添加至Key这个文本框,然后点击Add key。这个步骤的意思是,如果你想让jenkins通过ssh协议从gitlab拉取项目,需要认证,配置的公钥就是允许jenkins容器的jenkins用户所运行的jenkins从gitlab通过ssh协议拉取项目(有点别扭,但是需要注意的是jenkins这个容器主机和jenkins用户,jenkins程序是jenkins用户启动的)。
(这里有一个没有解决的问题,就是关于拉取private类型的项目,需要做的ssh认证,需要公钥密钥匹配,但是没有实现,所以暂时项目都是public。如果public的项目的话,可以通过http协议进行拉取,但是需不需要配置ssh的公钥,我也没试过,因该是不需要把。)

在配置好key之后,我们回到jenkins容器,当前用户为jenkins。我们想通过git客户端拉取项目的第二个准备工作,需要配置git的全局配置。

git  config --global   user.name=”yourName”

我的gitlab 和jenkins的用户都是jenkins,这里应该填写的是git用户名

git config –global user.email=”your email”

这两个配置完成后,我们可以就可以拉取项目到本地了,以我自己demo为例

git clone ssh://git@localhost:10022/jenkins/eurka.git

d.现在拉取到当前目录的eurka是个空项目,我们把我们要上传的项目源码和Dockerfile(用来jenkins调用docker打包镜像用的)添加至这个目录,然后git add ,git commit ,git push 命令将本地文件添加提交并推送整合至gitlab这个项目的某个分支下,默认是master

e.提交完成后,我们开始配置jenkins,以jenkins用户登录jenkins,新建,选择 --构建一个自由风格的软件项目然后确定

f.然后进入到这个项目的配置下,在源码管理选择Git,然后在Repository URL下,填入项目的ssh地址,注意这里不可一世用localhost,你可以填写主机的ip加上10022端口,也可以配置gitlab容器的ip地址加上22端口,我这里配置的是我的容器地址,例如ssh://git@172.18.0.4:22/jenkins/eurka.git,这里不要写10022端口!!!!因为是public项目,所以不需要添加认证
g.在构建触发器下,选择Build wher a chage is pushed to GitLab……….将后面的地址复制,然后在gitlab这个项目的Setting下的Integrations下,勾选Push Event,找到Add webhook,并填写刚才复制的路径,我这里写的依然是容器ip,http://172.18.0.5:8080/project/eurka,没有使用localhost:8888这个url,保存

h.回到jenkins的设置,在构建中下Execute shell下,编写shell脚本,这里就是gitlab被push后,通过webhook的方式让jenkins自动从gitlab下拉取项目之后,要执行的代码
默认拉取之后,会在这个项目的路径下,如果不确定自己当前的工作目录,可以通过echo $WORKDIR来查看当前位置,例如我的项目叫eurka,这个项目下我上传了一个maven项目,所以我如果想要对这个maven项目打包,我得进入这个项目目录,然后对这个项目下的pom文件进行操作,贴出我的shell:

#先打印当前位置
pwd
#进入到我的maven项目
cd spring-cloud-02-service
#maven打包
mvn clean compile package -Dmaven.test.skip=true
#回到上一级,因为上一级有Dockerfile文件
cd ../
#这里我先移除掉了我之前的镜像,然后再重新构建一个镜像,如果当前有#这个镜像运行的容器,需要先停止容器,移除容器,最后移除镜像
docker rmi 127.0.0.1:5000/auto/eurka:1.0 . || docker build -t 127.0.0.1:5000/auto/eurka:1.0 .
#将打包的镜像推送到本地的docker仓库
docker push 127.0.0.1:5000/auto/eurka:1.0
#查看本地是否打包成功
docker images
#最后可以执行docker run -itd –name container_name -p xxxx:xxxx  repo/im#g:tag /bin/bash让jenkins调用宿主机的docker,运行刚才打包好的镜像,不#出意外,应该在我们指定的端口上可以访问这个项目了。

最初我们在run jenkins容器的时候,将宿主机的docker文件挂载进了容器内部,这个操作很重要,但我也很迷糊,但可以肯定的是,jenkins容器所运行的docker及操作是针对宿主机的docker的

后续的持续集成,要基于kubernetes,kubernetes会自动的找其节点自动拉取刚push的镜像,并自动部署。未完待续

相关实践学习
通过workbench远程登录ECS,快速搭建Docker环境
本教程指导用户体验通过workbench远程登录ECS,完成搭建Docker环境的快速搭建,并使用Docker部署一个Nginx服务。
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
24天前
|
jenkins Java 持续交付
运用Jenkins实现Java项目的持续集成与自动化部署
在新建的Jenkins Job中,我们需要配置源码管理,通常选择Git、SVN等版本控制系统,并填入仓库地址和凭据。接着,设置构建触发器,如定时构建、轮询SCM变更、GitHub Webhook等方式,以便在代码提交后自动触发构建过程。
53 2
|
16天前
|
jenkins Java 测试技术
实现基于Jenkins的持续集成与部署
实现基于Jenkins的持续集成与部署
|
4天前
|
前端开发 JavaScript API
【Django+Vue3 线上教育平台项目实战】构建课程详情页与集成视频播放功能
随着数字化教育的兴起,构建一个高效、用户友好的线上教育平台至关重要。本文将探讨如何使用Django与Vue.js 3结合,实现一个包含课程列表和课程详情页(含视频播放功能)的线上教育平台部分。本文主要介绍了如何设计数据库模型、处理数据查询、构建动态前端界面,并集成视频播放功能,为用户带来流畅的学习体验。
【Django+Vue3 线上教育平台项目实战】构建课程详情页与集成视频播放功能
|
22天前
|
安全 关系型数据库 开发者
Docker Compose凭借其简单易用的特性,已经成为开发者在构建和管理多容器应用时不可或缺的工具。
Docker Compose是容器编排利器,简化多容器应用管理。通过YAML文件定义服务、网络和卷,一键启动应用环境。核心概念包括服务(组件集合)、网络(灵活通信)、卷(数据持久化)。实战中,编写docker-compose.yml,如设置Nginx和Postgres服务,用`docker-compose up -d`启动。高级特性涉及依赖、环境变量、健康检查和数据持久化。最佳实践涵盖环境隔离、CI/CD、资源管理和安全措施。案例分析展示如何构建微服务应用栈,实现一键部署。Docker Compose助力开发者高效驾驭复杂容器场景。
33 1
|
6天前
|
运维 Ubuntu Shell
阿里云云效操作报错合集之流水线构建Docker镜像时,遇到报错:“error: failed to solve: rpc error: code”,该怎么办
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
6天前
|
弹性计算 运维 Kubernetes
阿里云云效操作报错合集之构建流程中遇到 "origin_value 类型错误,取不到DOCKER_URL" 这样的错误,该怎么办
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
14天前
|
安全 容灾 jenkins
Java面试题:什么是Jenkins以及它在持续集成中的作用?Jenkins有哪些缺点呢?
Java面试题:什么是Jenkins以及它在持续集成中的作用?Jenkins有哪些缺点呢?
23 0
|
19天前
|
关系型数据库 MySQL 数据安全/隐私保护
Docker01,相关介绍,是快速构建、运行、管理应用的工具
Docker01,相关介绍,是快速构建、运行、管理应用的工具
|
1月前
|
Shell Docker 容器
深入探索Docker容器管理:常用命令一览(1)
深入探索Docker容器管理:常用命令一览(1)
|
2月前
|
Linux 开发者 Docker
如何构建在 Docker 容器中运行命令?
【1月更文挑战第6天】
91 0