in cli/azd/pkg/project/framework_service_docker.go [440:580]
func (p *dockerProject) packBuild(
ctx context.Context,
svc *ServiceConfig,
dockerOptions DockerProjectOptions,
imageName string) (*ServiceBuildResult, error) {
packCli, err := pack.NewCli(ctx, p.console, p.commandRunner)
if err != nil {
return nil, err
}
builder := DefaultBuilderImage
environ := []string{}
userDefinedImage := false
if os.Getenv("AZD_BUILDER_IMAGE") != "" {
builder = os.Getenv("AZD_BUILDER_IMAGE")
userDefinedImage = true
}
svcPath := svc.Path()
buildContext := svcPath
if svc.Docker.Context != "" {
buildContext = svc.Docker.Context
if !filepath.IsAbs(buildContext) {
buildContext = filepath.Join(svcPath, buildContext)
}
}
if !userDefinedImage {
// Always default to port 80 for consistency across languages
environ = append(environ, "ORYX_RUNTIME_PORT=80")
if svc.Language == ServiceLanguageJava {
environ = append(environ, "ORYX_RUNTIME_PORT=8080")
if buildContext != svcPath {
svcRelPath, err := filepath.Rel(buildContext, svcPath)
if err != nil {
return nil, fmt.Errorf("calculating relative context path: %w", err)
}
environ = append(environ, fmt.Sprintf("BP_MAVEN_BUILT_MODULE=%s", filepath.ToSlash(svcRelPath)))
}
}
if svc.OutputPath != "" && (svc.Language == ServiceLanguageTypeScript || svc.Language == ServiceLanguageJavaScript) {
inDockerOutputPath := path.Join("/workspace", svc.OutputPath)
// A dist folder has been set.
// We assume that the service is a front-end service, configuring a nginx web server to serve the static content
// produced.
environ = append(environ,
"ORYX_RUNTIME_IMAGE=nginx:1.25.2-bookworm",
fmt.Sprintf(
//nolint:lll
"ORYX_RUNTIME_SCRIPT=[ -d \"%s\" ] || { echo \"error: directory '%s' does not exist. ensure the 'dist' path in azure.yaml is specified correctly.\"; exit 1; } && "+
"rm -rf /usr/share/nginx/html && ln -sT %s /usr/share/nginx/html && "+
"nginx -g 'daemon off;'",
inDockerOutputPath,
svc.OutputPath,
inDockerOutputPath,
))
}
if svc.Language == ServiceLanguagePython {
pyEnviron, err := getEnvironForPython(ctx, svc)
if err != nil {
return nil, err
}
if len(pyEnviron) > 0 {
environ = append(environ, pyEnviron...)
}
}
}
previewer := p.console.ShowPreviewer(ctx,
&input.ShowPreviewerOptions{
Prefix: " ",
MaxLineCount: 8,
Title: "Docker (pack) Output",
})
ctx, span := tracing.Start(
ctx,
events.PackBuildEvent,
trace.WithAttributes(fields.ProjectServiceLanguageKey.String(string(svc.Language))))
img, tag := docker.SplitDockerImage(builder)
if userDefinedImage {
span.SetAttributes(
fields.StringHashed(fields.PackBuilderImage, img),
fields.StringHashed(fields.PackBuilderTag, tag),
)
} else {
span.SetAttributes(
fields.PackBuilderImage.String(img),
fields.PackBuilderTag.String(tag),
)
}
err = packCli.Build(
ctx,
buildContext,
builder,
imageName,
environ,
previewer)
p.console.StopPreviewer(ctx, false)
if err != nil {
span.EndWithStatus(err)
var statusCodeErr *pack.StatusCodeError
if errors.As(err, &statusCodeErr) && statusCodeErr.Code == pack.StatusCodeUndetectedNoError {
return nil, &internal.ErrorWithSuggestion{
Err: err,
Suggestion: "No Dockerfile was found, and image could not be automatically built from source. " +
fmt.Sprintf(
"\nSuggested action: Author a Dockerfile and save it as %s",
filepath.Join(svc.Path(), dockerOptions.Path)),
}
}
return nil, err
}
span.End()
imageId, err := p.docker.Inspect(ctx, imageName, "{{.Id}}")
if err != nil {
return nil, err
}
imageId = strings.TrimSpace(imageId)
return &ServiceBuildResult{
BuildOutputPath: imageId,
Details: &dockerBuildResult{
ImageId: imageId,
ImageName: imageName,
},
}, nil
}