GitLab-CI/CD入门实操
以Spring boot项目为例。传统方式是本地生成jar包,FTP上传服务器,重启服务;如果是内网测试服,也可以在服务器上安装git,在服务器上编译打包。但这都需要人为干预,于是CI/CD
就出现了。
- CI:Continuous Integration(持续集成)。自动构建和测试每次提交的代码,以确保所引入的更改符合所有测试、准则和代码合规性标准。
- CD:Continuous Delivery(持续交付)和Continuous Deployment(持续部署)。基于CI,前者侧重于交付给客户或质量团队(比如决定是否对新版本进行压测),而后手动部署/自动部署,如果是自动部署的话就是持续部署了。
CI/CD的工具有很多,最流行的当属jenkins
。不过以笔者为数不多的经验来看,作为后起之秀的gitlab更简单一点,也更灵活,不会像jenkins那样笨重。当然,两者的概念都是挺多的,没有师父,光靠自己入门都不容易。
GitLab-CI/CD流程示例
从左往右看,首先研发人员完成需求提交代码到 GitLab。GitLab 触发一次 Build,构建好服务,然后开始跑单元测试、集成测试。等待测试结果通过后,再由负责该项目的同事进行 CodeReview,灰度发布,正式部署到线上。
概念
本文基于GitLab 13.7版本
Pipline
Pipelines comprise:
- Jobs, which define what to do. For example, jobs that compile or test code.
- Stages, which define when to run the jobs. For example, stages that run tests after stages that compile the code.
Jobs are executed by runners
. Multiple jobs in the same stage are executed in parallel, if there are enough concurrent runners.
Stages
- Manage:项目周期或团队周期的各项数据统计分析。主要是各环节耗时统计,比如对于典型的Issue(提出问题)->Plan(列入计划)->Code(编码)->Test(测试)->Package(打包)流程,每个环节的耗时决定了整体问题处理的响应速度。
- Plan:借助诸多工具进行有效的项目管理。
- Create:代码管理。
- Verify:代码质量分析、代码合并(持续集成)、单元测试等。
- Package:将代码打包,并作为依赖库对外提供。
- Secure(ULTIMATE版提供):检查应用程序是否存在可能导致未经授权访问、数据泄漏或拒绝服务的安全漏洞。GitLab可以对应用程序的代码执行静态和动态测试,查找已知的缺陷并在合并请求中报告它们。然后可以在合并之前修复缺陷。安全团队可以使用仪表板获取项目和组的高级视图,并在需要时启动修正过程。
- Release:持续交付。
- Configure:配置[文件]参与DevOps各环节。
- Monitor:GitLab收集并显示已部署应用程序的性能指标,以便您可以立即知道代码更改如何影响生产环境。
- Defend:若干用于服务安全防御的中间件。
上述包含了GitLab-DevOps整个流程的所有环节,CI/CD只是其中的一部分。
GitLab Runner
可以安装在任意机子上,通过它可以[在一台机子上]注册多个runner
实例到gitlab服务器。每个runner用于执行一个或多个具体任务(如build、test)。
runner有以下三类,可用范围从大到小
Shared runners
are available to all groups and projects in a GitLab instance.Group runners
are available to all projects and subgroups in a group.Specific runners
are associated with specific projects. Typically, specific runners are used for one project at a time.
我们可以直接安装GitLab Runner到宿主机,也可以使用docker方式安装。注意这两种方式会影响到后续.gitlab-ci.yml
中对pipline
的定义。比如要编译maven项目,如果executor
设为shell,那么若宿主机中安装有mvn
命令,前者可以在scripts中直接使用mvn,而后者并不能,只能通过定义Dockerfile,在其中定义搭建mvn环境到编译代码的整个流程。
采用docker方式安装的话,可以参考Docker搭建自己的Gitlab CI Runner
docker pull gitlab/gitlab-runner:latest
docker run -d --name inkscreen-api-runner --restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest
注册runner实例
docker exec -it inkscreen-api-runner gitlab-runner register
会让我们填一系列配置项,如下:
Enter the GitLab instance URL (for example, https://gitlab.com/):
http://192.168.1.26:9980/
Enter the registration token:
cJMXGJWx7qx9AmpSc6ee
Enter a description for the runner:
[a0debaaf80a9]: runner for InkScreen-API project
Enter tags for the runner (comma-separated):
InkScreenAPI
Registering runner... succeeded runner=cJMXGJWx
Enter an executor: docker-ssh, shell, docker-ssh+machine, kubernetes, custom, parallels, ssh, virtualbox, docker+machine, docker:
docker
Enter the default Docker image (for example, ruby:2.6):
maven:3-jdk-8
完事后,我们在gitlab->xxxProjct中就能找到该runner:
接下来,就可以定义项目构建流程了。项目的构建流程是由项目根目录的.gitlab-ci.yml
文件控制的。当然了,一个pipeline可以涉及到多个runner。
.gitlab-ci.yml
定义一个pipline,以下为示例
variables:
DOCKER_TLS_CERTDIR: "/certs"
# stage也可以自定义
stages:
- build jar
# - test
- build and run image
#job's name 可以随意取
buildJar:
stage: build jar
variables:
# 若要使cache生效,须指定-Dmaven.repo.local
MAVEN_OPTS: "-Dmaven.repo.local=.m2"
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .m2
only:
- dev
script:
# package 已包含 test 步骤,所以流程中不需要另外配置test job
- mvn clean package
tags:
- inkscreen_api
artifacts:
paths:
- target/admin.jar
expire_in: 3600 seconds
deploy:
stage: build and run image
image: docker:stable
services:
- docker:dind
only:
- dev
variables:
IMAGE_NAME: newton/inkscreen-api:$CI_COMMIT_REF_NAME
PORT: 38082
script:
- docker build --build-arg JAR_PATH=target/admin.jar -t $IMAGE_NAME .
- docker run -p $PORT:$PORT -d --name inkscreen-$CI_COMMIT_REF_NAME --env spring.redis.host=myredis $IMAGE_NAME
tags:
- inkscreen_api
cache
cache
常用在dacker-based job之间传递文件。比如项目依赖的公共jar包,jobA辛辛苦苦从网上down了下来,结果运行完了,jobA所在容器也跟着被移除,自然里面的所有文件都不存在了。后续其它job用到相同的jar包还要重新下载。同样的,pipline多次执行,jobA自己每次也要重新下载。
为了解决这个问题,gitlab-ci采用了cache的方式。指定文件/目录,每次job结束前将其打包,放到/etc/gitlab-runner/config.toml
中对应的[runners.docker][volumes]指定的卷内,其它job(包括自己)运行前,对应的cache都会被加载并解压到容器内。
artifacts
artifacts
是job生成的中间产物,会以压缩包(.zip)的形式生成。它会自动上传到gitlab服务器,the artifacts will be downloaded and extracted in the context of later stages。所以它和cache很像,但是设计它们的初衷是不同的。
Don't use caching for passing artifacts between stages, as it is designed to store runtime dependencies needed to compile the project:
cache
: For storing project dependenciesCaches are used to speed up runs of a given job in subsequent pipelines, by storing downloaded dependencies so that they don't have to be fetched from the internet again (like npm packages, Go vendor packages, etc.) While the cache could be configured to pass intermediate build results between stages, this should be done with artifacts instead.
artifacts
: Use for stage results that will be passed between stages.Artifacts are files generated by a job which are stored and uploaded, and can then be fetched and used by jobs in later stages of the same pipeline. In other words, you can't create an artifact in job-A in stage-1, and then use this artifact in job-B in stage-1. This data will not be available in different pipelines, but is available to be downloaded from the UI.
The name artifacts sounds like it's only useful outside of the job, like for downloading a final image, but artifacts are also available in later stages within a pipeline.
另外,同样key的cache会被覆盖,而artifacts一旦生成就固定了,当然我们可以设置expire_in
,过期删除之。
实战
我们定义一个最简单的pipline:第一步编译生成jar包,第二步将jar包导入docker镜像并运行,在某些环节还需加入代码review。因为最后我们会以docker容器运行jar包,所以这里不建议docker-based runner/executor的形式,因为该形式导致Docker-in-Docker
的场景,带来可能的一些麻烦且难以解决的问题(比如内嵌容器如何关联外部服务以及对外提供服务)。所以我们直接宿主机安装GitLab Runner。
如果一定要以docker-based形式,那么可参看使用GitLab CI和Docker自动部署SpringBoot应用。在该文中,并没有在runner所在宿主机中运行容器,而是将生成的镜像发布到镜像仓库,再登录目标服务器拉取镜像运行,所以不存在Docker-in-Docker的麻烦事。
安装&注册[GitLab ]Runner
# 1.Add the official GitLab repository
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash
# 2.Install the latest version of GitLab Runner
export GITLAB_RUNNER_DISABLE_SKEL=true; sudo -E yum install gitlab-runner
注册runner
sudo gitlab-runner register -n \
--url http://192.168.1.26:9980/ \
--registration-token cJMXGJWx7qx9AmpSc6ee \
--executor shell \
--tag-list "inkscreen_hostrunner" \
--description "Host Runner for InkScreen"
Add the gitlab-runner user to the docker group:
sudo usermod -aG docker gitlab-runner
.gitlab-ci.yml
stages:
- build jar
- build and run image
#job's name 可以随意取
buildJar:
stage: build jar
variables:
# 默认是clone,改为fetch加快拉取速度(若本地无则会自动clone)
GIT_STRATEGY: fetch
only:
- dev
script:
- >
docker run -d --rm --name justforpackage-$CI_COMMIT_REF_NAME
-v "$(pwd)":/build/inkscreen
-v /inkscreen/maven/m2:/root/.m2
-w /build/inkscreen
maven:3-jdk-8 mvn clean package
- sleep 60
tags:
- inkscreen_hostrunner
artifacts:
paths:
- louwen-admin/target/louwen-admin.jar
expire_in: 3600 seconds
testDeploy:
stage: build and run image
only:
- dev
variables:
# 不拉取代码
GIT_STRATEGY: none
IMAGE_NAME: louwen/inkscreen-api:$CI_COMMIT_REF_NAME
PORT: 38082
before_script:
# 移除旧容器和镜像。这里为什么要写成一行,下面有讲
- if [ docker ps | grep inkscreen-$CI_COMMIT_REF_NAME ]; then docker stop inkscreen-$CI_COMMIT_REF_NAME; docker rm inkscreen-$CI_COMMIT_REF_NAME; docker rmi $IMAGE_NAME; fi
script:
- docker build --build-arg JAR_PATH=louwen-admin/target/louwen-admin.jar -t $IMAGE_NAME .
- >
docker run -d --name inkscreen-$CI_COMMIT_REF_NAME
-p $PORT:$PORT
--network my_bridge --env spring.redis.host=myredis
-v /inkscreen/inkscreen-api/logs/:/logs/
-v /inkscreen/inkscreen-api/louwen-admin/src/main/resources/:/configs/
$IMAGE_NAME
tags:
- inkscreen_hostrunner
注意build jar环节我们sleep了60秒,是因为docker run并不会等待内部脚本执行完,而是启动后就直接返回了,此时jar包尚未生成,所以此处阻塞一段时间等待打包结束。正常应该写一段脚本循环判断jar包是否已生成,若生成或超时则跳出循环,此处作为演示简单sleep。
在testDeploy任务中,before_script被我写成了一行,最初版本是:
before_script:
# 若未找到记录,则该条命令会返回1,gitlab就直接报错返回了ERROR: Job failed: exit status 1
- docker ps | grep inkscreen-$CI_COMMIT_REF_NAME
- >
if [ $? -eq 0 ]
then
docker stop inkscreen-$CI_COMMIT_REF_NAME
docker rm inkscreen-$CI_COMMIT_REF_NAME
docker rmi $IMAGE_NAME
fi
后改为
before_script:
# 将检测语句直接作为条件内置,解决了上面的问题
- >
if
docker ps | grep inkscreen-$CI_COMMIT_REF_NAME
then
docker stop inkscreen-$CI_COMMIT_REF_NAME
docker rm inkscreen-$CI_COMMIT_REF_NAME
docker rmi $IMAGE_NAME
fi
报错syntax error near unexpected token 'fi'
,估计是换行/回车格式的原因。上述两个问题都可以通过单独建.sh文件的方式解决,我这里简单地将所有语句排成一行。
Dockerfile
生成镜像自然少不了Dockerfile
FROM openjdk:8-jdk-oracle
MAINTAINER louwen
# 外部传入,主程序路径
ARG JAR_PATH
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
COPY $JAR_PATH /app.jar
EXPOSE 38082
ENTRYPOINT ["java","-jar","/app.jar"]
题外话,其实我们完全可以将build jar环节也放在Dockerfile中,如下
#
# build jar stage
#
FROM maven:3-jdk-8 AS MAVEN_BUILD
COPY pom.xml /build/
COPY src /build/src/
WORKDIR /build/
RUN mvn clean package
#
FROM openjdk:8-jdk-oracle
MAINTAINER louwen
COPY --from=MAVEN_BUILD /build/target/*.jar /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
代码规范
目前较流行的代码检测工具是SonarQube,不过其社区版本对同一个代码仓库无法区分不同分支,从而实现按代码的不同分支显示对应分支的扫描结果。这里我们使用Gitlab-CI的Code Quality stage
,其使用的是Codeclimate
,它是为代码质量分析平台提供的一个命令行接口工具,通过它可以在本机 Docker 容器中对要分析的代码执行质量分析,并生成分析报告。我们熟知常用的代码质量检测工具例如 SonarQube、CheckStyle 等等,而 Codeclimate 接入了这些工具,而且支持我们自定义检测工具。
按照官方说法,使用Code Quality
需要基于docker-based runner/executor,所以我们另外使用docker方式安装GitLab-Runner并注册一个runner(参考上述概念
小节),executor选择docker。
include:
- template: Code-Quality.gitlab-ci.yml
# 以下配置参考网上一些资料,据说是官方示例,然而我没有在官方文档找到
code_quality:
image: docker:stable
variables:
DOCKER_DRIVER: overlay2
# gitlab 13.6及之后版本支持
REPORT_FORMAT: html
allow_failure: true
services:
- docker:dind
script:
# 镜像版本号格式参看 https://gitlab.com/gitlab-org/ci-cd/codequality/-/tree/master#versioning-and-release-cycle
# - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run
--net=host
--env SOURCE_CODE="$PWD"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:${VERSION:-latest}" /code
artifacts:
paths: [ gl-code-quality-report.html ]
tags:
- InkScreenAPI
执行的时候可能会卡在拉取镜像环节。手动docker pull registry.gitlab.com/gitlab-org/security-products/codequality:latest
,发现各种超时。我开个阿里云香港ECS的抢占式实例(便宜)然后docker pull | save | load
将镜像文件迁移到公司测试服,还是报Unable to find image 'registry.gitlab.com/gitlab-org/security-products/codequality:latest' locally
,不知如何将host中的镜像映射到docker:stable
中。看来还是得kexue上网。
理论上,需要专人在合适的时候对提交的代码进行质量把关,一般这工作可以放在Merge Request
下进行。Merge Request的工作流程可以参看在团队中使用GitLab中的Merge Request工作模式
FAQ
dial tcp: lookup docker on 192.168.1.1:53: no such host
错误。
This error occurs with docker-based gitlab runners such as the one we’re that are configured using a docker executor. The error message means that the inner docker container doesn’t have a connection to the host docker daemon.
解决:将/etc/gitlab-runner/config.toml
中对应的[runners.docker]节点设置privileged = true
,增加卷映射volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
或在.gitlab-ci.yml的job定义中增加services: - docker:dind
。Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?
错误
解决:增加卷映射volumes = ["/certs/client", "/cache"]
,然后在.gitlab-ci.yml中增加变量DOCKER_TLS_CERTDIR: "/certs"
。拉取代码时提示
warning: failed to remove xxxx: Permission denied
简单粗暴地编辑/etc/passwd,将gitlab-runner账号对应的uid:gid
改为0:0
(和root一样)。Code Quality提示
docker: Error response from daemon: Head https://registry.gitlab.com/v2/gitlab-org/security-products/codequality/manifests/13-7-stable: Get https://gitlab.com/jwt/auth?scope=repository%3Agitlab-org%2Fsecurity-products%2Fcodequality%3Apull&service=container_registry: dial tcp [2606:4700:90:0:f22e:fbec:5bed:a9b9]:443: connect: cannot assign requested address.
在scripts->docker run增加参数--net=host
其它
发件邮箱配置
在pipline流程执行过程中,我们希望有任何风吹草动都能及时收到消息,邮件就是一个比较好的提醒方式。
vi /etc/gitlab/gitlab.rb
### GitLab email server settings
###! Docs: https://docs.gitlab.com/omnibus/settings/smtp.html
###! **Use smtp instead of sendmail/postfix.**
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.exmail.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "xxxx@yyyy.com"
gitlab_rails['smtp_password'] = "xxxxxxxx"
gitlab_rails['smtp_domain'] = "exmail.qq.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
### Email Settings
gitlab_rails['gitlab_email_enabled'] = true
##! If your SMTP server does not like the default 'From: gitlab@gitlab.example.com'
##! can change the 'From' with this setting.
##! 要与上面的 smtp_user_name 保持一致
gitlab_rails['gitlab_email_from'] = 'xxxx@yyyy.com'
# gitlab_rails['gitlab_email_display_name'] = 'Example'
# gitlab_rails['gitlab_email_reply_to'] = 'noreply@example.com'
# gitlab_rails['gitlab_email_subject_suffix'] = ''
# gitlab_rails['gitlab_email_smime_enabled'] = false
# gitlab_rails['gitlab_email_smime_key_file'] = '/etc/gitlab/ssl/gitlab_smime.key'
# gitlab_rails['gitlab_email_smime_cert_file'] = '/etc/gitlab/ssl/gitlab_smime.crt'
# gitlab_rails['gitlab_email_smime_ca_certs_file'] = '/etc/gitlab/ssl/gitlab_smime_cas.crt'
gitlab-ctl reconfigure
使配置生效
测试
gitlab-rails console
irb(main):003:0> Notify.test_email('whatever@qq.com', 'Message Subject', 'Message Body').deliver_now
登录whatever@qq.com查看受否收到信件。
jenkins + gitlab
如果使用jenkins作为CI/CD工具,代码由gitlab托管,那么它们之间的交互需要两个token:
- api token,用于jenkins调用gitlab api使用
- ssh密钥对,jenkins拉取代码使用(当然我们也可以使用用户名/密码方式拉取)
mvn package、install、deploy都干了什么
- mvn clean package依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)等7个阶段。
- mvn clean install依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)、install等8个阶段。
- mvn clean deploy依次执行了clean、resources、compile、testResources、testCompile、test、jar(打包)、install、deploy等9个阶段。
由上可知:
- package命令完成了项目编译、单元测试、打包功能,但没有把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库
- install命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库,但没有布署到远程maven私服仓库
- deploy命令完成了项目编译、单元测试、打包功能,同时把打好的可执行jar包(war包或其它形式的包)布署到本地maven仓库和远程maven私服仓库
alpine
Alpine Linux
是一个社区开发的面向安全应用的轻量级Linux发行版。很多镜像都会专门基于Alpine构建,大小会小很多。比如:
- gitlab/gitlab-runner:latest based on Ubuntu.
- gitlab/gitlab-runner:alpine based on Alpine with much a smaller footprint (~160/350 MB Ubuntu vs ~45/130 MB Alpine compressed/decompressed).
修改GitLab-ce域名
刚部署好的GitLab新建的项目ssh地址一般是个短链接如git@AKDJF3ld:xxx,有时候会不太好使,可以通过配置文件的修改,指向域名。
vim /opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml
# host: 192.168.xx.xx
# port: xxxx
gitlab-ctl restart
参考资料
当谈到 GitLab CI 的时候,我们该聊些什么(上篇)
什么是devops,基于Gitlab从零开始搭建自己的持续集成流水线(Pipeline)
持续集成之.gitlab-ci.yml篇
Building Docker images with GitLab CI/CD
自动化 DevOps 使用 Codeclimate 执行代码质量分析
GitLab CI/CD
基于 Gitlab 的 Code Review 最佳实践
GitLab-CI/CD入门实操的更多相关文章
- GitLab CI/CD的官译【原】
CI / CD方法简介 软件开发的持续集成基于自动执行脚本,以最大限度地减少在开发应用程序时引入错误的可能性.从新代码的开发到部署,它们需要较少的人为干预甚至根本不需要干预. 它涉及在每次小迭代中不断 ...
- GitLab CI/CD 自动化部署入门
前言:因为找了B站内推,测试开发,正好知道内部使用GitLab做自动化测试,所以简单学了一下,有错误的地方请指正. 入门 初始化 cp: 无法获取'/root/node-v12.9.0-linux-x ...
- 实践分享!GitLab CI/CD 快速入门
用过 GitLab 的同学肯定也对 GitLab CI/CD 不陌生,GitLab CI/CD 是一个内置在 GitLab 中的工具,它可以帮助我们在每次代码推送时运行一系列脚本来构建.测试和验证代码 ...
- [转]GitLab Continuous Integration (GitLab CI/CD)
本文转自:https://docs.gitlab.com/ee/ci/README.html GitLab Continuous Integration (GitLab CI/CD) The bene ...
- 使用 Gitlab CI/CD 实现自动化发布站点到 IIS
说明 这里先介绍下两个东西 CI/CD.GitLab Runner,当然在此之前你需要对 git 有所了解,关于 git 这里不做说明,可以自行百度. 首先介绍 CI/CD :随着我们开发方式的转变, ...
- 前端初探 Gitlab CI/CD
前言 纵观人类历史的发展以及三次工业革命,你会发现利用机器来替代部分人力劳动,将重复的工作自动化从而解放生产力都是发展的必然趋势,在软件工程领域也不例外,其中 CI/CD 就是其中一项,那么什么是 C ...
- .Net Core自动化部署系列(三):使用GitLab CI/CD 自动部署Api到Docker
之前写过使用Jenkins实现自动化部署,最近正好没事研究了下GitLab的自动化部署,顺便记录一下. 使用GitLab部署我们需要准备两件事,第一个起码你得有个GitLab,自己搭建或者使用官方的都 ...
- GitLab CI/CD持续集成设置
GitLab CI/CD持续设置 官方文档地址(https://docs.gitlab.com/ee/ci/README.html) GitLab CI.CD功能非常完善,只需要简单几步,就可以完成项 ...
- Gitlab CI/CD
Gitlab CI/CD 前言 纵观人类历史的发展以及三次工业革命,你会发现利用机器来替代部分人力劳动,将重复的工作自动化从而解放生产力都是发展的必然趋势,在软件工程领域也不例外,其中 CI/CD 就 ...
随机推荐
- 跟我一起学Redis之高可用从主从复制开始
前言 现在遇到高并发场景时,缓存技术应该算是性能优化的第一步,缓解数据库压力的同时还能提高访问效率,而Redis应该是绝大多数应用场景的首选.但是尽快Redis性能再优秀,在当今高并发场景下,一台服务 ...
- DRF终极封装ViewSet和Router附教程PDF源码
在DRF官方教程的学习过程中,一个很明显的感受是框架在不断地进行封装,我们自己写框架/工具/脚本/平台也可以模仿模仿,先完成底层代码,再做多层封装,让使用者很容易就上手操作.本文是教程的最后一篇,介绍 ...
- Docker Container 就是一个进程,多新鲜啊?
大家对 Docker 都应该有了或多或少的认识了,相信大家都是从这两张图来粗旷的理解 Docker 及容器概念的 那我们如何更轻松的理解容器 Container 呢?说白了 Container 就是一 ...
- Visual Studio 2013中安装Resharper之后一些快捷键无法使用,比如F6和F12
快捷键是一个很好用的东西,尤其对于计算机从业者来说,好的快捷键能够高程度提高工作效率.像我们程序员经常需要团队开发,我们会遇到一个问题,那就是快捷键不一致问题,我一般会安装resharper,但是有的 ...
- java如何实现入职时间到现在 java如何计算知道入职时间, 求工作时长格式为年--月--日。
Date ruZhi = new Date("入职年月bai"); Date now = new Date(); //算出du来时间夸格zhi多长 long shiChang = ...
- VS Code 自动化连接非固定IP地址EC2实例的解决方案
问题描述 大家可能和我一样,平时在AWS上启动一台安装有Linux EC2实例作为远程开发机. (注:这里的EC2实例是配置用私钥进行登录的) 通常,你可以选择申请一个Elastic IP绑定到这台开 ...
- Kubernetes项目简介
Kubernetes项目简介 Kubernetes 是 Google 团队发起的开源项目,它的目标是管理跨多个主机的容器,提供基本的部署,维护以及运用伸缩,主要实现语言为 Go 语言.Kubernet ...
- TurtleBot3 Waffle (tx2版华夫)(9)建图-gmapping建图(A2雷达)
9.1. 说明 这一节我们来讲 Turtlebot3 的 SLAMSLAM(The Simultaneous Localization and Mapping) 同步定位与地图构建: 希望机器人从未知 ...
- Redis--部署操作
1.Redis 1.1 安装 当前ubuntu虚拟机中已经安装好了redis,以下步骤可以跳过 以后自己安装过程如下:redis下载链接:x 指的是版本号 http://download.redis. ...
- GitHub基础使用指南
引言: 只要进行了一段时间的软件或者编程相关知识的学习,相信大家或多或少都会见过这只"猫猫",这可不是什么宠物店铺的商标,身为即将成为程序猿/媛的你,或者已经是一位程序猿/媛的你, ...