Skip to content

Commit ccd7e99

Browse files
committed
feat(builder): add cloud native buildpacks support
1 parent aa06bcc commit ccd7e99

15 files changed

Lines changed: 142 additions & 426 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The builder is primarily a git server that responds to `git push`es by executing
2424
- Otherwise, if `BUILDER_STORAGE` is `minio` and the `DRYCC_MINIO_SERVICE_HOST` and `DRYCC_MINIO_SERVICE_PORT` environment variables exist (these are standard [Kubernetes service discovery environment variables](http://kubernetes.io/docs/user-guide/services/#environment-variables)), saves to the [S3 API][s3-api-ref] compatible server at `http://$DRYCC_MINIO_SERVICE_HOST:$DRYCC_MINIO_SERVICE_HOST`
2525
3. Starts a new [Kubernetes Pod](http://kubernetes.io/docs/user-guide/pods/) to build the code, according to the following rules:
2626
- If a `Dockerfile` is present in the codebase, starts a [`imagebuilder`](https://github.com/drycc/imagebuilder) pod, configured to download the code to build from the URL computed in the previous step.
27-
- Otherwise, starts a [`slugbuilder`](https://github.com/drycc/slugbuilder) pod, configured to download the code to build from the URL computed in the previous step.
27+
- Otherwise, starts a [`buildpacker`](https://github.com/drycc/buildpacker) pod, configured to download the code to build from the URL computed in the previous step.
2828

2929
# Supported Off-Cluster Storage Backends
3030

charts/builder/templates/builder-deployment.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ spec:
5858
# Set GIT_LOCK_TIMEOUT to number of minutes you want to wait to git push again to the same repository
5959
- name: "GIT_LOCK_TIMEOUT"
6060
value: "30"
61-
- name: SLUGBUILDER_IMAGE_PULL_POLICY
61+
- name: buildpackER_IMAGE_PULL_POLICY
6262
valueFrom:
6363
configMapKeyRef:
64-
name: slugbuilder-config
64+
name: build pa c ker-config
6565
key: image_pull_policy
6666
- name: IMAGEBUILDER_IMAGE_PULL_POLICY
6767
valueFrom:
@@ -108,8 +108,8 @@ spec:
108108
- name: objectstore-creds
109109
mountPath: /var/run/secrets/drycc/objectstore/creds
110110
readOnly: true
111-
- name: slugbuilder-config
112-
mountPath: /etc/slugbuilder
111+
- name: buildpacker-config
112+
mountPath: /etc/buildpacker
113113
readOnly: true
114114
- name: imagebuilder-config
115115
mountPath: /etc/imagebuilder
@@ -124,9 +124,9 @@ spec:
124124
- name: objectstore-creds
125125
secret:
126126
secretName: objectstorage-keyfile
127-
- name: slugbuilder-config
127+
- name: buildpacker-config
128128
configMap:
129-
name: slugbuilder-config
129+
name: buildpacker-config
130130
- name: imagebuilder-config
131131
configMap:
132132
name: imagebuilder-config

pkg/builder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Package pkg provides common libraries for the Drycc builder.
22
//
3-
// The Drycc builder is responsible for building slugs and docker images for use in the Drycc
3+
// The Drycc builder is responsible for building buildpack and docker images for use in the Drycc
44
// on the Drycc PaaS platform.
55
package pkg
66

pkg/cleaner/cleaner.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/drycc/builder/pkg/sys"
1919
"github.com/drycc/pkg/log"
2020
corev1 "k8s.io/api/core/v1"
21+
2122
//"k8s.io/apimachinery/pkg/labels"
2223
//"k8s.io/apimachinery/pkg/fields"
2324
//"k8s.io/apimachinery/pkg/apis/meta/internalversion"
@@ -89,17 +90,7 @@ func dirHasGitSuffix(dir string) bool {
8990

9091
func deleteFromObjectStore(app string, storageDriver storagedriver.StorageDriver) error {
9192

92-
cacheKey := fmt.Sprintf(gitreceive.CacheKeyPattern, app)
93-
94-
// if cache file exists, delete it
95-
if _, err := storageDriver.Stat(context.Background(), cacheKey); err == nil {
96-
log.Info("Cleaner deleting cache %s for app %s", cacheKey, app)
97-
if err := storageDriver.Delete(context.Background(), cacheKey); err != nil {
98-
return err
99-
}
100-
}
101-
102-
// delete all slug files matching app
93+
// delete all files matching app
10394
objs, err := storageDriver.List(context.Background(), "home")
10495
if err != nil {
10596
return err
@@ -113,7 +104,7 @@ func deleteFromObjectStore(app string, storageDriver storagedriver.StorageDriver
113104

114105
for _, obj := range objs {
115106
if gitRegex.MatchString(obj) {
116-
log.Info("Cleaner deleting slug %s for app %s", obj, app)
107+
log.Info("Cleaner deleting %s for app %s", obj, app)
117108
if err := storageDriver.Delete(context.Background(), obj); err != nil {
118109
return err
119110
}

pkg/gitreceive/build.go

Lines changed: 60 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ import (
3030
"k8s.io/client-go/kubernetes/scheme"
3131
)
3232

33+
const (
34+
// TarKeyPattern is the template for storing tar key files.
35+
TarKeyPattern = "%s/tar"
36+
// GitKeyPattern is the template for storing git key files.
37+
GitKeyPattern = "home/%s:git-%s"
38+
)
39+
3340
// repoCmd returns exec.Command(first, others...) with its current working directory repoDir
3441
func repoCmd(repoDir, first string, others ...string) *exec.Cmd {
3542
cmd := exec.Command(first, others...)
@@ -62,16 +69,6 @@ func build(
6269
// Rewrite regular expression, compatible with slug type
6370
storagedriver.PathRegexp = regexp.MustCompile(`^([A-Za-z0-9._:-]*(/[A-Za-z0-9._:-]+)*)+$`)
6471

65-
imagebuilderImagePullPolicy, err := k8s.PullPolicyFromString(conf.ImagebuilderImagePullPolicy)
66-
if err != nil {
67-
return err
68-
}
69-
70-
slugBuilderImagePullPolicy, err := k8s.PullPolicyFromString(conf.SlugBuilderImagePullPolicy)
71-
if err != nil {
72-
return err
73-
}
74-
7572
repo := conf.Repository
7673
gitSha, err := git.NewSha(rawGitSha)
7774
if err != nil {
@@ -83,7 +80,6 @@ func build(
8380
repoDir := filepath.Join(conf.GitHome, repo)
8481
buildDir := filepath.Join(repoDir, "build")
8582

86-
slugName := fmt.Sprintf("%s:git-%s", appName, gitSha.Short())
8783
if err := os.MkdirAll(buildDir, os.ModeDir); err != nil {
8884
return fmt.Errorf("making the build directory %s (%s)", buildDir, err)
8985
}
@@ -109,20 +105,6 @@ func build(
109105
return err
110106
}
111107

112-
_, disableCaching := appConf.Values["DRYCC_DISABLE_CACHE"]
113-
slugBuilderInfo := NewSlugBuilderInfo(appName, gitSha.Short(), disableCaching)
114-
115-
if slugBuilderInfo.DisableCaching() {
116-
log.Debug("caching disabled for app %s", appName)
117-
// If cache file exists, delete it
118-
if _, err := storageDriver.Stat(context.Background(), slugBuilderInfo.CacheKey()); err == nil {
119-
log.Debug("deleting cache %s for app %s", slugBuilderInfo.CacheKey(), appName)
120-
if err := storageDriver.Delete(context.Background(), slugBuilderInfo.CacheKey()); err != nil {
121-
return err
122-
}
123-
}
124-
}
125-
126108
// build a tarball from the new objects
127109
appTgz := fmt.Sprintf("%s.tar.gz", appName)
128110
gitArchiveCmd := repoCmd(repoDir, "git", "archive", "--format=tar.gz", fmt.Sprintf("--output=%s", appTgz), gitSha.Short())
@@ -148,83 +130,65 @@ func build(
148130
return fmt.Errorf("error while reading file %s: (%s)", appTgz, err)
149131
}
150132

151-
log.Debug("Uploading tar to %s", slugBuilderInfo.TarKey())
133+
tarKey := fmt.Sprintf(TarKeyPattern, fmt.Sprintf(GitKeyPattern, appName, gitSha.Short()))
134+
log.Debug("Uploading tar to %s", tarKey)
152135

153-
if err := storageDriver.PutContent(context.Background(), slugBuilderInfo.TarKey(), appTgzdata); err != nil {
154-
return fmt.Errorf("uploading %s to %s (%v)", absAppTgz, slugBuilderInfo.TarKey(), err)
136+
if err := storageDriver.PutContent(context.Background(), tarKey, appTgzdata); err != nil {
137+
return fmt.Errorf("uploading %s to %s (%v)", absAppTgz, tarKey, err)
155138
}
156139

157-
var pod *corev1.Pod
158-
var buildPodName string
159-
image := appName
160-
161140
builderPodNodeSelector, err := buildBuilderPodNodeSelector(conf.BuilderPodNodeSelector)
162141
if err != nil {
163142
return fmt.Errorf("error build builder pod node selector %s", err)
164143
}
165144

145+
var builderName string
146+
var imagePullPolicy corev1.PullPolicy
147+
var securityContext corev1.SecurityContext
166148
if strings.Contains(stack["name"], "container") {
167-
buildPodName = imagebuilderPodName(appName, gitSha.Short())
168-
registryLocation := conf.RegistryLocation
169-
registryEnv := make(map[string]string)
170-
if registryLocation != "on-cluster" {
171-
registryEnv, err = getRegistryDetails(kubeClient.CoreV1(), &image, registryLocation, conf.PodNamespace)
172-
if err != nil {
173-
return fmt.Errorf("error getting private registry details %s", err)
174-
}
175-
image = image + ":git-" + gitSha.Short()
176-
}
177-
registryEnv["DRYCC_REGISTRY_LOCATION"] = registryLocation
178-
179-
pod = imagebuilderPod(
180-
conf.Debug,
181-
buildPodName,
182-
conf.PodNamespace,
183-
appConf.Values,
184-
slugBuilderInfo.TarKey(),
185-
gitSha.Short(),
186-
slugName,
187-
conf.StorageType,
188-
stack["image"],
189-
conf.RegistryHost,
190-
conf.RegistryPort,
191-
registryEnv,
192-
imagebuilderImagePullPolicy,
193-
builderPodNodeSelector,
194-
)
149+
builderName = "drycc-imagebuilder"
150+
imagePullPolicy, err = k8s.PullPolicyFromString(conf.ImagebuilderImagePullPolicy)
151+
securityContext = k8s.SecurityContextFromPrivileged(false)
152+
195153
} else {
196-
buildPodName = slugBuilderPodName(appName, gitSha.Short())
154+
builderName = "drycc-buildpacker"
155+
imagePullPolicy, err = k8s.PullPolicyFromString(conf.BuildpackerImagePullPolicy)
156+
securityContext = k8s.SecurityContextFromPrivileged(true)
157+
}
158+
if err != nil {
159+
return err
160+
}
197161

198-
cacheKey := ""
199-
if !slugBuilderInfo.DisableCaching() {
200-
cacheKey = slugBuilderInfo.CacheKey()
201-
}
202-
envSecretName := fmt.Sprintf("%s-build-env", appName)
203-
err = createAppEnvConfigSecret(kubeClient.CoreV1().Secrets(conf.PodNamespace), envSecretName, appConf.Values)
162+
imageName := fmt.Sprintf("%s:git-%s", appName, gitSha.Short())
163+
buildPodName := imagebuilderPodName(appName, gitSha.Short())
164+
registryLocation := conf.RegistryLocation
165+
registryEnv := make(map[string]string)
166+
if registryLocation != "on-cluster" {
167+
registryEnv, err = getRegistryDetails(kubeClient.CoreV1(), &imageName, registryLocation, conf.PodNamespace)
204168
if err != nil {
205-
return fmt.Errorf("error creating/updating secret %s: (%s)", envSecretName, err)
169+
return fmt.Errorf("error getting private registry details %s", err)
206170
}
207-
defer func() {
208-
if err := kubeClient.CoreV1().Secrets(conf.PodNamespace).Delete(ctx.TODO(), envSecretName, metav1.DeleteOptions{}); err != nil {
209-
log.Info("unable to delete secret %s (%s)", envSecretName, err)
210-
}
211-
}()
212-
pod = slugbuilderPod(
213-
conf.Debug,
214-
buildPodName,
215-
conf.PodNamespace,
216-
appConf.Values,
217-
envSecretName,
218-
slugBuilderInfo.TarKey(),
219-
slugBuilderInfo.PushKey(),
220-
cacheKey,
221-
gitSha.Short(),
222-
conf.StorageType,
223-
stack["image"],
224-
slugBuilderImagePullPolicy,
225-
builderPodNodeSelector,
226-
)
227171
}
172+
registryEnv["DRYCC_REGISTRY_LOCATION"] = registryLocation
173+
174+
pod := createBuilderPod(
175+
conf.Debug,
176+
buildPodName,
177+
conf.PodNamespace,
178+
appConf.Values,
179+
tarKey,
180+
gitSha.Short(),
181+
imageName,
182+
conf.StorageType,
183+
builderName,
184+
stack["image"],
185+
conf.RegistryHost,
186+
conf.RegistryPort,
187+
registryEnv,
188+
imagePullPolicy,
189+
securityContext,
190+
builderPodNodeSelector,
191+
)
228192

229193
log.Info("Starting build... but first, coffee!")
230194
log.Debug("Use image %s: %s", stack["name"], stack["image"])
@@ -296,7 +260,7 @@ func build(
296260
}
297261
log.Debug("Done")
298262

299-
procType, err := getProcFile(storageDriver, tmpDir, slugBuilderInfo.AbsoluteProcfileKey(), stack)
263+
procType, err := getProcfile(storageDriver, tmpDir, stack)
300264
if err != nil {
301265
return err
302266
}
@@ -305,10 +269,7 @@ func build(
305269

306270
quit := progress("...", conf.SessionIdleInterval())
307271
log.Info("Launching App...")
308-
if stack["name"] != "container" {
309-
image = slugBuilderInfo.AbsoluteSlugObjectKey()
310-
}
311-
release, err := hooks.CreateBuild(client, conf.Username, conf.App(), image, stack["name"], gitSha.Short(), procType, stack["name"] == "container")
272+
release, err := hooks.CreateBuild(client, conf.Username, conf.App(), imageName, stack["name"], gitSha.Short(), procType, stack["name"] == "container")
312273
quit <- true
313274
<-quit
314275
if controller.CheckAPICompat(client, err) != nil {
@@ -350,8 +311,12 @@ func prettyPrintJSON(data interface{}) (string, error) {
350311
return formatted.String(), nil
351312
}
352313

353-
func getProcFile(getter storage.ObjectGetter, dirName, procfileKey string, stack map[string]string) (dryccAPI.ProcessType, error) {
314+
func getProcfile(getter storage.ObjectGetter, dirName string, stack map[string]string) (dryccAPI.ProcessType, error) {
354315
procType := dryccAPI.ProcessType{}
316+
_, err := os.Stat(fmt.Sprintf("%s/project.toml", dirName))
317+
if err == nil || stack["name"] == "container" {
318+
return procType, nil
319+
}
355320
if _, err := os.Stat(fmt.Sprintf("%s/Procfile", dirName)); err == nil {
356321
rawProcFile, err := ioutil.ReadFile(fmt.Sprintf("%s/Procfile", dirName))
357322
if err != nil {
@@ -362,16 +327,5 @@ func getProcFile(getter storage.ObjectGetter, dirName, procfileKey string, stack
362327
}
363328
return procType, nil
364329
}
365-
if stack["name"] == "container" {
366-
return procType, nil
367-
}
368-
log.Debug("Procfile not present. Getting it from the buildpack")
369-
rawProcFile, err := getter.GetContent(context.Background(), procfileKey)
370-
if err != nil {
371-
return nil, fmt.Errorf("error in reading %s (%s)", procfileKey, err)
372-
}
373-
if err := yaml.Unmarshal(rawProcFile, &procType); err != nil {
374-
return nil, fmt.Errorf("procfile %s is malformed (%s)", procfileKey, err)
375-
}
376-
return procType, nil
330+
return nil, fmt.Errorf("no Procfile can be matched in (%s)", dirName)
377331
}

0 commit comments

Comments
 (0)